1# Licensed under the Apache License, Version 2.0 (the "License"); you may 2# not use this file except in compliance with the License. You may obtain 3# a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations 11# under the License. 12 13from unittest import mock 14 15from keystoneauth1 import adapter 16 17from openstack.baremetal.v1 import node as _node 18from openstack.baremetal_introspection.v1 import _proxy 19from openstack.baremetal_introspection.v1 import introspection 20from openstack import exceptions 21from openstack.tests.unit import base 22from openstack.tests.unit import test_proxy_base 23 24 25@mock.patch.object(introspection.Introspection, 'create', autospec=True) 26class TestStartIntrospection(base.TestCase): 27 28 def setUp(self): 29 super(TestStartIntrospection, self).setUp() 30 self.session = mock.Mock(spec=adapter.Adapter) 31 self.proxy = _proxy.Proxy(self.session) 32 33 def test_create_introspection(self, mock_create): 34 self.proxy.start_introspection('abcd') 35 mock_create.assert_called_once_with(mock.ANY, self.proxy) 36 introspect = mock_create.call_args[0][0] 37 self.assertEqual('abcd', introspect.id) 38 39 def test_create_introspection_with_node(self, mock_create): 40 self.proxy.start_introspection(_node.Node(id='abcd')) 41 mock_create.assert_called_once_with(mock.ANY, self.proxy) 42 introspect = mock_create.call_args[0][0] 43 self.assertEqual('abcd', introspect.id) 44 45 def test_create_introspection_manage_boot(self, mock_create): 46 self.proxy.start_introspection('abcd', manage_boot=False) 47 mock_create.assert_called_once_with(mock.ANY, self.proxy, 48 manage_boot=False) 49 introspect = mock_create.call_args[0][0] 50 self.assertEqual('abcd', introspect.id) 51 52 53class TestBaremetalIntrospectionProxy(test_proxy_base.TestProxyBase): 54 55 def setUp(self): 56 super(TestBaremetalIntrospectionProxy, self).setUp() 57 self.proxy = _proxy.Proxy(self.session) 58 59 def test_get_introspection(self): 60 self.verify_get(self.proxy.get_introspection, 61 introspection.Introspection) 62 63 64@mock.patch('time.sleep', lambda _sec: None) 65@mock.patch.object(introspection.Introspection, 'fetch', autospec=True) 66class TestWaitForIntrospection(base.TestCase): 67 68 def setUp(self): 69 super(TestWaitForIntrospection, self).setUp() 70 self.session = mock.Mock(spec=adapter.Adapter) 71 self.proxy = _proxy.Proxy(self.session) 72 self.fake = {'state': 'waiting', 'error': None, 'finished': False} 73 self.introspection = introspection.Introspection(**self.fake) 74 75 def test_already_finished(self, mock_fetch): 76 self.introspection.is_finished = True 77 self.introspection.state = 'finished' 78 result = self.proxy.wait_for_introspection(self.introspection) 79 self.assertIs(result, self.introspection) 80 self.assertFalse(mock_fetch.called) 81 82 def test_wait(self, mock_fetch): 83 marker = [False] # mutable object to modify in the closure 84 85 def _side_effect(allocation, session): 86 if marker[0]: 87 self.introspection.state = 'finished' 88 self.introspection.is_finished = True 89 else: 90 self.introspection.state = 'processing' 91 marker[0] = True 92 93 mock_fetch.side_effect = _side_effect 94 result = self.proxy.wait_for_introspection(self.introspection) 95 self.assertIs(result, self.introspection) 96 self.assertEqual(2, mock_fetch.call_count) 97 98 def test_timeout(self, mock_fetch): 99 self.assertRaises(exceptions.ResourceTimeout, 100 self.proxy.wait_for_introspection, 101 self.introspection, 102 timeout=0.001) 103 mock_fetch.assert_called_with(self.introspection, self.proxy) 104 105 def test_failure(self, mock_fetch): 106 def _side_effect(allocation, session): 107 self.introspection.state = 'error' 108 self.introspection.is_finished = True 109 self.introspection.error = 'boom' 110 111 mock_fetch.side_effect = _side_effect 112 self.assertRaisesRegex(exceptions.ResourceFailure, 'boom', 113 self.proxy.wait_for_introspection, 114 self.introspection) 115 mock_fetch.assert_called_once_with(self.introspection, self.proxy) 116 117 def test_failure_ignored(self, mock_fetch): 118 def _side_effect(allocation, session): 119 self.introspection.state = 'error' 120 self.introspection.is_finished = True 121 self.introspection.error = 'boom' 122 123 mock_fetch.side_effect = _side_effect 124 result = self.proxy.wait_for_introspection(self.introspection, 125 ignore_error=True) 126 self.assertIs(result, self.introspection) 127 mock_fetch.assert_called_once_with(self.introspection, self.proxy) 128 129 130@mock.patch.object(_proxy.Proxy, 'request', autospec=True) 131class TestAbortIntrospection(base.TestCase): 132 133 def setUp(self): 134 super(TestAbortIntrospection, self).setUp() 135 self.session = mock.Mock(spec=adapter.Adapter) 136 self.proxy = _proxy.Proxy(self.session) 137 self.fake = {'id': '1234', 'finished': False} 138 self.introspection = introspection.Introspection(**self.fake) 139 140 def test_abort(self, mock_request): 141 mock_request.return_value.status_code = 202 142 self.proxy.abort_introspection(self.introspection) 143 mock_request.assert_called_once_with( 144 self.proxy, 'introspection/1234/abort', 'POST', 145 headers=mock.ANY, microversion=mock.ANY, 146 retriable_status_codes=[409, 503]) 147 148 149@mock.patch.object(_proxy.Proxy, 'request', autospec=True) 150class TestGetData(base.TestCase): 151 152 def setUp(self): 153 super(TestGetData, self).setUp() 154 self.session = mock.Mock(spec=adapter.Adapter) 155 self.proxy = _proxy.Proxy(self.session) 156 self.fake = {'id': '1234', 'finished': False} 157 self.introspection = introspection.Introspection(**self.fake) 158 159 def test_get_data(self, mock_request): 160 mock_request.return_value.status_code = 200 161 data = self.proxy.get_introspection_data(self.introspection) 162 mock_request.assert_called_once_with( 163 self.proxy, 'introspection/1234/data', 'GET', 164 headers=mock.ANY, microversion=mock.ANY) 165 self.assertIs(data, mock_request.return_value.json.return_value) 166 167 def test_get_unprocessed_data(self, mock_request): 168 mock_request.return_value.status_code = 200 169 data = self.proxy.get_introspection_data(self.introspection, 170 processed=False) 171 mock_request.assert_called_once_with( 172 self.proxy, 'introspection/1234/data/unprocessed', 'GET', 173 headers=mock.ANY, microversion='1.17') 174 self.assertIs(data, mock_request.return_value.json.return_value) 175