1# Copyright (c) 2017 DataCore Software Corp. All Rights Reserved. 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"""Unit tests for classes that are used to invoke DataCore SANsymphony API.""" 16 17import mock 18from oslo_utils import units 19import six 20import suds 21from suds.sax import parser 22from suds import wsdl 23 24from cinder import test 25from cinder.volume.drivers.datacore import api 26from cinder.volume.drivers.datacore import exception 27 28 29class FakeWebSocketException(Exception): 30 pass 31 32 33class DataCoreClientTestCase(test.TestCase): 34 """Tests for the DataCore SANsymphony client.""" 35 36 def setUp(self): 37 super(DataCoreClientTestCase, self).setUp() 38 self.mock_storage_services = mock.MagicMock() 39 self.mock_executive_service = mock.MagicMock() 40 41 self.mock_suds_client = mock.MagicMock() 42 self.mock_object( 43 api.suds_client, 'Client', return_value=self.mock_suds_client) 44 45 self.mock_channel = mock.MagicMock() 46 mock_websocket = self.mock_object(api, 'websocket') 47 mock_websocket.WebSocketException = FakeWebSocketException 48 mock_websocket.create_connection.return_value = self.mock_channel 49 50 setattr(self.mock_suds_client.service.__getitem__, 51 'side_effect', 52 self._get_service_side_effect) 53 54 self.client = api.DataCoreClient('hostname', 'username', 'password', 1) 55 self.client.API_RETRY_INTERVAL = 0 56 57 def _get_service_side_effect(self, service_name): 58 self.assertIn(service_name, 59 [ 60 api.DataCoreClient.STORAGE_SERVICES_BINDING, 61 api.DataCoreClient.EXECUTIVE_SERVICE_BINDING 62 ]) 63 64 if service_name is api.DataCoreClient.STORAGE_SERVICES_BINDING: 65 return self.mock_storage_services 66 else: 67 return self.mock_executive_service 68 69 def _assert_storage_services_method_called(self, method_name): 70 return self.mock_storage_services.__getitem__.assert_called_with( 71 method_name) 72 73 @property 74 def mock_storage_service_context(self): 75 return self.mock_storage_services.__getitem__()() 76 77 @property 78 def mock_executive_service_context(self): 79 return self.mock_executive_service.__getitem__()() 80 81 def test_process_request_failed(self): 82 def fail_with_socket_error(): 83 raise FakeWebSocketException() 84 85 def fail_with_web_fault(message): 86 fault = mock.Mock() 87 fault.faultstring = "General error." 88 document = mock.Mock() 89 raise suds.WebFault(fault, document) 90 91 self.mock_channel.recv.side_effect = fail_with_socket_error 92 self.assertRaises(exception.DataCoreConnectionException, 93 self.client.get_server_groups) 94 self.mock_channel.recv.side_effect = None 95 96 (self.mock_storage_service_context.process_reply 97 .side_effect) = fail_with_web_fault 98 self.assertRaises(exception.DataCoreFaultException, 99 self.client.get_server_groups) 100 101 def test_channel_closing_failed(self): 102 def fail_with_socket_error(): 103 raise FakeWebSocketException() 104 105 def fail_with_web_fault(message): 106 fault = mock.Mock() 107 fault.faultstring = "General error." 108 document = mock.Mock() 109 raise suds.WebFault(fault, document) 110 111 self.mock_channel.close.side_effect = fail_with_socket_error 112 (self.mock_storage_service_context.process_reply 113 .side_effect) = fail_with_web_fault 114 self.assertRaises(exception.DataCoreFaultException, 115 self.client.get_server_groups) 116 117 def test_update_api_endpoints(self): 118 def fail_with_socket_error(): 119 try: 120 raise FakeWebSocketException() 121 finally: 122 self.mock_channel.recv.side_effect = None 123 124 self.mock_channel.recv.side_effect = fail_with_socket_error 125 126 mock_executive_endpoints = [{ 127 'network_address': '127.0.0.1:3794', 128 'http_endpoint': 'http://127.0.0.1:3794/', 129 'ws_endpoint': 'ws://127.0.0.1:3794/', 130 }] 131 self.mock_object(self.client, 132 '_executive_service_endpoints', 133 mock_executive_endpoints) 134 135 mock_storage_endpoint = { 136 'network_address': '127.0.0.1:3794', 137 'http_endpoint': 'http://127.0.0.1:3794/', 138 'ws_endpoint': 'ws://127.0.0.1:3794/', 139 } 140 self.mock_object(self.client, 141 '_storage_services_endpoint', 142 mock_storage_endpoint) 143 144 node = mock.Mock() 145 node.HostAddress = '127.0.0.1:3794' 146 reply = mock.MagicMock() 147 reply.RegionNodeData = [node] 148 self.mock_storage_service_context.process_reply.return_value = reply 149 150 result = self.client.get_server_groups() 151 self.assertIsNotNone(result) 152 153 def test_update_api_endpoints_failed(self): 154 def fail_with_socket_error(): 155 try: 156 raise FakeWebSocketException() 157 finally: 158 self.mock_channel.recv.side_effect = None 159 160 self.mock_channel.recv.side_effect = fail_with_socket_error 161 162 mock_executive_endpoints = [{ 163 'network_address': '127.0.0.1:3794', 164 'http_endpoint': 'http://127.0.0.1:3794/', 165 'ws_endpoint': 'ws://127.0.0.1:3794/', 166 }] 167 self.mock_object(self.client, 168 '_executive_service_endpoints', 169 mock_executive_endpoints) 170 171 reply = mock.MagicMock() 172 reply.RegionNodeData = [] 173 self.mock_storage_service_context.process_reply.return_value = reply 174 175 self.mock_executive_service_context.process_reply.return_value = None 176 177 result = self.client.get_server_groups() 178 self.assertIsNotNone(result) 179 180 def test_get_server_groups(self): 181 self.client.get_server_groups() 182 self._assert_storage_services_method_called('GetServerGroups') 183 184 def test_get_servers(self): 185 self.client.get_servers() 186 self._assert_storage_services_method_called('GetServers') 187 188 def test_get_disk_pools(self): 189 self.client.get_disk_pools() 190 self._assert_storage_services_method_called('GetDiskPools') 191 192 def test_get_logical_disks(self): 193 self.client.get_logical_disks() 194 self._assert_storage_services_method_called('GetLogicalDisks') 195 196 def test_create_pool_logical_disk(self): 197 pool_id = 'pool_id' 198 pool_volume_type = 'Striped' 199 size = 1 * units.Gi 200 min_quota = 1 201 max_quota = 1 * units.Gi 202 self.client.create_pool_logical_disk( 203 pool_id, pool_volume_type, size, min_quota, max_quota) 204 self._assert_storage_services_method_called('CreatePoolLogicalDisk') 205 206 def test_delete_logical_disk(self): 207 logical_disk_id = 'disk_id' 208 self.client.delete_logical_disk(logical_disk_id) 209 self._assert_storage_services_method_called('DeleteLogicalDisk') 210 211 def test_get_logical_disk_chunk_allocation_map(self): 212 logical_disk_id = 'disk_id' 213 self.client.get_logical_disk_chunk_allocation_map(logical_disk_id) 214 self._assert_storage_services_method_called( 215 'GetLogicalDiskChunkAllocationMap') 216 217 def test_get_next_virtual_disk_alias(self): 218 base_alias = 'volume' 219 self.client.get_next_virtual_disk_alias(base_alias) 220 self._assert_storage_services_method_called('GetNextVirtualDiskAlias') 221 222 def test_get_virtual_disks(self): 223 self.client.get_virtual_disks() 224 self._assert_storage_services_method_called('GetVirtualDisks') 225 226 def test_build_virtual_disk_data(self): 227 disk_alias = 'alias' 228 disk_type = 'Mirrored' 229 size = 1 * units.Gi 230 description = 'description' 231 storage_profile_id = 'storage_profile_id' 232 233 vd_data = self.client.build_virtual_disk_data( 234 disk_alias, disk_type, size, description, storage_profile_id) 235 236 self.assertEqual(disk_alias, vd_data.Alias) 237 self.assertEqual(size, vd_data.Size.Value) 238 self.assertEqual(description, vd_data.Description) 239 self.assertEqual(storage_profile_id, vd_data.StorageProfileId) 240 self.assertTrue(hasattr(vd_data, 'Type')) 241 self.assertTrue(hasattr(vd_data, 'SubType')) 242 self.assertTrue(hasattr(vd_data, 'DiskStatus')) 243 self.assertTrue(hasattr(vd_data, 'RecoveryPriority')) 244 245 def test_create_virtual_disk_ex2(self): 246 disk_alias = 'alias' 247 disk_type = 'Mirrored' 248 size = 1 * units.Gi 249 description = 'description' 250 storage_profile_id = 'storage_profile_id' 251 first_disk_id = 'disk_id' 252 second_disk_id = 'disk_id' 253 add_redundancy = True 254 vd_data = self.client.build_virtual_disk_data( 255 disk_alias, disk_type, size, description, storage_profile_id) 256 self.client.create_virtual_disk_ex2( 257 vd_data, first_disk_id, second_disk_id, add_redundancy) 258 self._assert_storage_services_method_called('CreateVirtualDiskEx2') 259 260 def test_set_virtual_disk_size(self): 261 disk_id = 'disk_id' 262 size = 1 * units.Gi 263 self.client.set_virtual_disk_size(disk_id, size) 264 self._assert_storage_services_method_called('SetVirtualDiskSize') 265 266 def test_delete_virtual_disk(self): 267 virtual_disk_id = 'disk_id' 268 delete_logical_disks = True 269 self.client.delete_virtual_disk(virtual_disk_id, delete_logical_disks) 270 self._assert_storage_services_method_called('DeleteVirtualDisk') 271 272 def test_serve_virtual_disks_to_host(self): 273 host_id = 'host_id' 274 disks = ['disk_id'] 275 self.client.serve_virtual_disks_to_host(host_id, disks) 276 self._assert_storage_services_method_called('ServeVirtualDisksToHost') 277 278 def test_unserve_virtual_disks_from_host(self): 279 host_id = 'host_id' 280 disks = ['disk_id'] 281 self.client.unserve_virtual_disks_from_host(host_id, disks) 282 self._assert_storage_services_method_called( 283 'UnserveVirtualDisksFromHost') 284 285 def test_unserve_virtual_disks_from_port(self): 286 port_id = 'port_id' 287 disks = ['disk_id'] 288 self.client.unserve_virtual_disks_from_port(port_id, disks) 289 self._assert_storage_services_method_called( 290 'UnserveVirtualDisksFromPort') 291 292 def test_bind_logical_disk(self): 293 disk_id = 'disk_id' 294 logical_disk_id = 'disk_id' 295 role = 'Second' 296 create_mirror_mappings = True 297 create_client_mappings = False 298 add_redundancy = True 299 self.client.bind_logical_disk( 300 disk_id, logical_disk_id, role, create_mirror_mappings, 301 create_client_mappings, add_redundancy) 302 self._assert_storage_services_method_called( 303 'BindLogicalDisk') 304 305 def test_get_snapshots(self): 306 self.client.get_snapshots() 307 self._assert_storage_services_method_called('GetSnapshots') 308 309 def test_create_snapshot(self): 310 disk_id = 'disk_id' 311 name = 'name' 312 description = 'description' 313 pool_id = 'pool_id' 314 snapshot_type = 'Full' 315 duplicate_disk_id = False 316 storage_profile_id = 'profile_id' 317 self.client.create_snapshot( 318 disk_id, name, description, pool_id, snapshot_type, 319 duplicate_disk_id, storage_profile_id) 320 self._assert_storage_services_method_called('CreateSnapshot') 321 322 def test_delete_snapshot(self): 323 snapshot_id = "snapshot_id" 324 self.client.delete_snapshot(snapshot_id) 325 self._assert_storage_services_method_called('DeleteSnapshot') 326 327 def test_get_storage_profiles(self): 328 self.client.get_storage_profiles() 329 self._assert_storage_services_method_called('GetStorageProfiles') 330 331 def test_designate_map_store(self): 332 pool_id = 'pool_id' 333 self.client.designate_map_store(pool_id) 334 self._assert_storage_services_method_called('DesignateMapStore') 335 336 def test_get_performance_by_type(self): 337 types = ['DiskPoolPerformance'] 338 self.client.get_performance_by_type(types) 339 self._assert_storage_services_method_called('GetPerformanceByType') 340 341 def test_get_ports(self): 342 self.client.get_ports() 343 self._assert_storage_services_method_called('GetPorts') 344 345 def test_build_scsi_port_data(self): 346 host_id = 'host_id' 347 port_name = 'port_name' 348 port_mode = 'Initiator' 349 port_type = 'iSCSI' 350 351 port_data = self.client.build_scsi_port_data( 352 host_id, port_name, port_mode, port_type) 353 354 self.assertEqual(host_id, port_data.HostId) 355 self.assertEqual(port_name, port_data.PortName) 356 self.assertTrue(hasattr(port_data, 'PortMode')) 357 self.assertTrue(hasattr(port_data, 'PortType')) 358 359 def test_register_port(self): 360 port_data = self.client.build_scsi_port_data( 361 'host_id', 'port_name', 'initiator', 'iSCSI') 362 self.client.register_port(port_data) 363 self._assert_storage_services_method_called('RegisterPort') 364 365 def test_assign_port(self): 366 client_id = 'client_id' 367 port_id = 'port_id' 368 self.client.assign_port(client_id, port_id) 369 self._assert_storage_services_method_called('AssignPort') 370 371 def test_set_server_port_properties(self): 372 port_id = 'port_id' 373 port_properties = mock.MagicMock() 374 self.client.set_server_port_properties(port_id, port_properties) 375 self._assert_storage_services_method_called('SetServerPortProperties') 376 377 def test_build_access_token(self): 378 initiator_node_name = 'initiator' 379 initiator_username = 'initiator_username' 380 initiator_password = 'initiator_password' 381 mutual_authentication = True 382 target_username = 'target_username' 383 target_password = 'target_password' 384 385 access_token = self.client.build_access_token( 386 initiator_node_name, initiator_username, initiator_password, 387 mutual_authentication, target_username, target_password) 388 389 self.assertEqual(initiator_node_name, access_token.InitiatorNodeName) 390 self.assertEqual(initiator_username, access_token.InitiatorUsername) 391 self.assertEqual(initiator_password, access_token.InitiatorPassword) 392 self.assertEqual(mutual_authentication, 393 access_token.MutualAuthentication) 394 self.assertEqual(target_username, access_token.TargetUsername) 395 self.assertEqual(target_password, access_token.TargetPassword) 396 397 def test_set_access_token(self): 398 port_id = 'port_id' 399 access_token = self.client.build_access_token( 400 'initiator_name', None, None, False, 'initiator_name', 'password') 401 self.client.set_access_token(port_id, access_token) 402 self._assert_storage_services_method_called('SetAccessToken') 403 404 def test_get_clients(self): 405 self.client.get_clients() 406 self._assert_storage_services_method_called('GetClients') 407 408 def test_register_client(self): 409 host_name = 'name' 410 description = 'description' 411 machine_type = 'Other' 412 mode = 'PreferredServer' 413 preferred_server_ids = None 414 self.client.register_client( 415 host_name, description, machine_type, mode, preferred_server_ids) 416 self._assert_storage_services_method_called('RegisterClient') 417 418 def test_set_client_capabilities(self): 419 client_id = 'client_id' 420 mpio = True 421 alua = True 422 self.client.set_client_capabilities(client_id, mpio, alua) 423 self._assert_storage_services_method_called('SetClientCapabilities') 424 425 def test_get_target_domains(self): 426 self.client.get_target_domains() 427 self._assert_storage_services_method_called('GetTargetDomains') 428 429 def test_create_target_domain(self): 430 initiator_host_id = 'host_id' 431 target_host_id = 'host_id' 432 self.client.create_target_domain(initiator_host_id, target_host_id) 433 self._assert_storage_services_method_called('CreateTargetDomain') 434 435 def test_delete_target_domain(self): 436 domain_id = 'domain_id' 437 self.client.delete_target_domain(domain_id) 438 self._assert_storage_services_method_called('DeleteTargetDomain') 439 440 def test_get_target_devices(self): 441 self.client.get_target_devices() 442 self._assert_storage_services_method_called('GetTargetDevices') 443 444 def test_build_scsi_port_nexus_data(self): 445 initiator_id = 'initiator_id' 446 target_id = 'target_id' 447 448 nexus = self.client.build_scsi_port_nexus_data(initiator_id, target_id) 449 450 self.assertEqual(initiator_id, nexus.InitiatorPortId) 451 self.assertEqual(target_id, nexus.TargetPortId) 452 453 def test_create_target_device(self): 454 domain_id = 'domain_id' 455 nexus = self.client.build_scsi_port_nexus_data('initiator_id', 456 'target_id') 457 self.client.create_target_device(domain_id, nexus) 458 self._assert_storage_services_method_called('CreateTargetDevice') 459 460 def test_delete_target_device(self): 461 device_id = 'device_id' 462 self.client.delete_target_device(device_id) 463 self._assert_storage_services_method_called('DeleteTargetDevice') 464 465 def test_get_next_free_lun(self): 466 device_id = 'device_id' 467 self.client.get_next_free_lun(device_id) 468 self._assert_storage_services_method_called('GetNextFreeLun') 469 470 def test_get_logical_units(self): 471 self.client.get_logical_units() 472 self._assert_storage_services_method_called('GetLogicalUnits') 473 474 def test_map_logical_disk(self): 475 disk_id = 'disk_id' 476 lun = 0 477 host_id = 'host_id' 478 mapping_type = 'Client' 479 initiator_id = 'initiator_id' 480 target_id = 'target_id' 481 nexus = self.client.build_scsi_port_nexus_data(initiator_id, target_id) 482 self.client.map_logical_disk( 483 disk_id, nexus, lun, host_id, mapping_type) 484 self._assert_storage_services_method_called('MapLogicalDisk') 485 486 def test_unmap_logical_disk(self): 487 logical_disk_id = 'disk_id' 488 nexus = self.client.build_scsi_port_nexus_data('initiator_id', 489 'target_id') 490 self.client.unmap_logical_disk(logical_disk_id, nexus) 491 self._assert_storage_services_method_called('UnmapLogicalDisk') 492 493 494FAKE_WSDL_DOCUMENT = """<?xml version="1.0" encoding="utf-8"?> 495<wsdl:definitions name="ExecutiveServices" 496 targetNamespace="http://tempuri.org/" 497 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 498 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 499 xmlns:tns="http://tempuri.org/" 500 xmlns:wsa10="http://www.w3.org/2005/08/addressing" 501 xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"> 502 <wsdl:types> 503 <xs:schema elementFormDefault="qualified" 504 targetNamespace="http://tempuri.org/" 505 xmlns:xs="http://www.w3.org/2001/XMLSchema"> 506 <xs:import 507namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/> 508 <xs:import 509namespace="http://schemas.datacontract.org/2004/07/DataCore.Executive"/> 510 <xs:element name="StartExecutive"> 511 <xs:complexType> 512 <xs:sequence/> 513 </xs:complexType> 514 </xs:element> 515 <xs:element name="StartExecutiveResponse"> 516 <xs:complexType> 517 <xs:sequence/> 518 </xs:complexType> 519 </xs:element> 520 <xs:element name="StopExecutive"> 521 <xs:complexType> 522 <xs:sequence/> 523 </xs:complexType> 524 </xs:element> 525 <xs:element name="StopExecutiveResponse"> 526 <xs:complexType> 527 <xs:sequence/> 528 </xs:complexType> 529 </xs:element> 530 <xs:element name="ExecutiveStarted"> 531 <xs:complexType> 532 <xs:sequence/> 533 </xs:complexType> 534 </xs:element> 535 <xs:element name="ExecutiveStopped"> 536 <xs:complexType> 537 <xs:sequence/> 538 </xs:complexType> 539 </xs:element> 540 </xs:schema> 541 </wsdl:types> 542 <wsdl:message name="IExecutiveServiceEx_StartExecutive_InputMessage"> 543 <wsdl:part name="parameters" element="tns:StartExecutive"/> 544 </wsdl:message> 545 <wsdl:message name="IExecutiveServiceEx_StartExecutive_OutputMessage"> 546 <wsdl:part name="parameters" element="tns:StartExecutiveResponse"/> 547 </wsdl:message> 548 <wsdl:message 549name="IExecutiveServiceEx_StartExecutive_ExecutiveError_FaultMessage"> 550 <wsdl:part name="detail" element="ExecutiveError"/> 551 </wsdl:message> 552 <wsdl:message name="IExecutiveServiceEx_StopExecutive_InputMessage"> 553 <wsdl:part name="parameters" element="tns:StopExecutive"/> 554 </wsdl:message> 555 <wsdl:message name="IExecutiveServiceEx_StopExecutive_OutputMessage"> 556 <wsdl:part name="parameters" element="tns:StopExecutiveResponse"/> 557 </wsdl:message> 558 <wsdl:message 559name="IExecutiveServiceEx_StopExecutive_ExecutiveError_FaultMessage"> 560 <wsdl:part name="detail" element="ExecutiveError"/> 561 </wsdl:message> 562 <wsdl:message 563 name="IExecutiveServiceEx_ExecutiveStarted_OutputCallbackMessage"> 564 <wsdl:part name="parameters" element="tns:ExecutiveStarted"/> 565 </wsdl:message> 566 <wsdl:message 567name="IExecutiveServiceEx_ExecutiveStopped_OutputCallbackMessage"> 568 <wsdl:part name="parameters" element="tns:ExecutiveStopped"/> 569 </wsdl:message> 570 <wsdl:portType name="IExecutiveServiceEx"> 571 <wsdl:operation name="StartExecutive"> 572 <wsdl:input 573wsaw:Action="http://tempuri.org/IExecutiveService/StartExecutive" 574message="tns:IExecutiveServiceEx_StartExecutive_InputMessage"/> 575 <wsdl:output 576wsaw:Action="http://tempuri.org/IExecutiveService/StartExecutiveResponse" 577message="tns:IExecutiveServiceEx_StartExecutive_OutputMessage"/> 578 <wsdl:fault wsaw:Action="ExecutiveError" name="ExecutiveError" 579message="tns:IExecutiveServiceEx_StartExecutive_ExecutiveError_FaultMessage"/> 580 </wsdl:operation> 581 <wsdl:operation name="StopExecutive"> 582 <wsdl:input 583wsaw:Action="http://tempuri.org/IExecutiveService/StopExecutive" 584message="tns:IExecutiveServiceEx_StopExecutive_InputMessage"/> 585 <wsdl:output 586wsaw:Action="http://tempuri.org/IExecutiveService/StopExecutiveResponse" 587message="tns:IExecutiveServiceEx_StopExecutive_OutputMessage"/> 588 <wsdl:fault wsaw:Action="ExecutiveError" name="ExecutiveError" 589message="tns:IExecutiveServiceEx_StopExecutive_ExecutiveError_FaultMessage"/> 590 </wsdl:operation> 591 <wsdl:operation name="ExecutiveStarted"> 592 <wsdl:output 593wsaw:Action="http://tempuri.org/IExecutiveService/ExecutiveStarted" 594message="tns:IExecutiveServiceEx_ExecutiveStarted_OutputCallbackMessage"/> 595 <wsdl:fault wsaw:Action="ExecutiveError" name="ExecutiveError" 596 message="tns:"/> 597 </wsdl:operation> 598 <wsdl:operation name="ExecutiveStopped"> 599 <wsdl:output 600wsaw:Action="http://tempuri.org/IExecutiveService/ExecutiveStopped" 601message="tns:IExecutiveServiceEx_ExecutiveStopped_OutputCallbackMessage"/> 602 <wsdl:fault wsaw:Action="ExecutiveError" name="ExecutiveError" 603 message="tns:"/> 604 </wsdl:operation> 605 </wsdl:portType> 606 <wsdl:binding name="CustomBinding_IExecutiveServiceEx" 607 type="tns:IExecutiveServiceEx"> 608 <soap:binding transport="http://schemas.microsoft.com/soap/websocket"/> 609 <wsdl:operation name="StartExecutive"> 610 <soap:operation 611soapAction="http://tempuri.org/IExecutiveService/StartExecutive" 612 style="document"/> 613 <wsdl:input> 614 <soap:body use="literal"/> 615 </wsdl:input> 616 <wsdl:output> 617 <soap:body use="literal"/> 618 </wsdl:output> 619 <wsdl:fault name="ExecutiveError"> 620 <soap:fault use="literal" name="ExecutiveError" namespace=""/> 621 </wsdl:fault> 622 </wsdl:operation> 623 <wsdl:operation name="StopExecutive"> 624 <soap:operation 625soapAction="http://tempuri.org/IExecutiveService/StopExecutive" 626 style="document"/> 627 <wsdl:input> 628 <soap:body use="literal"/> 629 </wsdl:input> 630 <wsdl:output> 631 <soap:body use="literal"/> 632 </wsdl:output> 633 <wsdl:fault name="ExecutiveError"> 634 <soap:fault use="literal" name="ExecutiveError" namespace=""/> 635 </wsdl:fault> 636 </wsdl:operation> 637 <wsdl:operation name="ExecutiveStarted"> 638 <soap:operation 639soapAction="http://tempuri.org/IExecutiveService/ExecutiveStarted" 640 style="document"/> 641 <wsdl:output> 642 <soap:body use="literal"/> 643 </wsdl:output> 644 <wsdl:fault name="ExecutiveError"> 645 <soap:fault use="literal" name="ExecutiveError" namespace=""/> 646 </wsdl:fault> 647 </wsdl:operation> 648 <wsdl:operation name="ExecutiveStopped"> 649 <soap:operation 650soapAction="http://tempuri.org/IExecutiveService/ExecutiveStopped" 651 style="document"/> 652 <wsdl:output> 653 <soap:body use="literal"/> 654 </wsdl:output> 655 <wsdl:fault name="ExecutiveError"> 656 <soap:fault use="literal" name="ExecutiveError" namespace=""/> 657 </wsdl:fault> 658 </wsdl:operation> 659 </wsdl:binding> 660 <wsdl:service name="ExecutiveServices"> 661 <wsdl:port name="CustomBinding_IExecutiveServiceEx" 662 binding="tns:CustomBinding_IExecutiveServiceEx"> 663 <soap:address 664 location="ws://mns-vsp-001:3794/IExecutiveServiceEx"/> 665 <wsa10:EndpointReference> 666 <wsa10:Address>ws://mns-vsp-001:3794/IExecutiveServiceEx 667 </wsa10:Address> 668 </wsa10:EndpointReference> 669 </wsdl:port> 670 </wsdl:service> 671</wsdl:definitions>""" 672 673 674class FaultDefinitionsFilterTestCase(test.TestCase): 675 """Tests for the plugin to process the DataCore API WSDL document.""" 676 677 @staticmethod 678 def _binding_operation_has_fault(document, operation_name): 679 for binding in document.getChildren('binding', wsdl.wsdlns): 680 for operation in binding.getChildren('operation', wsdl.wsdlns): 681 if operation.get('name') == operation_name: 682 fault = operation.getChildren('fault', wsdl.wsdlns) 683 if fault: 684 return True 685 return False 686 687 @staticmethod 688 def _port_type_operation_has_fault(document, operation_name): 689 for port_type in document.getChildren('portType', wsdl.wsdlns): 690 for operation in port_type.getChildren('operation', wsdl.wsdlns): 691 if operation.get('name') == operation_name: 692 fault = operation.getChildren('fault', wsdl.wsdlns) 693 if fault: 694 return True 695 return False 696 697 def _operation_has_fault(self, document, operation_name): 698 _binding_has_fault = self._binding_operation_has_fault( 699 document, operation_name) 700 _port_type_has_fault = self._port_type_operation_has_fault( 701 document, operation_name) 702 self.assertEqual(_binding_has_fault, _port_type_has_fault) 703 return _binding_has_fault 704 705 def test_parsed(self): 706 context = mock.Mock() 707 sax = parser.Parser() 708 wsdl_document = FAKE_WSDL_DOCUMENT 709 if isinstance(wsdl_document, six.text_type): 710 wsdl_document = wsdl_document.encode('utf-8') 711 context.document = sax.parse(string=wsdl_document).root() 712 self.assertTrue(self._operation_has_fault(context.document, 713 'StartExecutive')) 714 self.assertTrue(self._operation_has_fault(context.document, 715 'StopExecutive')) 716 self.assertTrue(self._operation_has_fault(context.document, 717 'ExecutiveStarted')) 718 self.assertTrue(self._operation_has_fault(context.document, 719 'ExecutiveStopped')) 720 plugin = api.FaultDefinitionsFilter() 721 plugin.parsed(context) 722 self.assertTrue(self._operation_has_fault(context.document, 723 'StartExecutive')) 724 self.assertTrue(self._operation_has_fault(context.document, 725 'StopExecutive')) 726 self.assertFalse(self._operation_has_fault(context.document, 727 'ExecutiveStarted')) 728 self.assertFalse(self._operation_has_fault(context.document, 729 'ExecutiveStopped')) 730