Skip to content

Commit dc6490c

Browse files
committed
add test for validating network actions
1 parent d0b7791 commit dc6490c

File tree

6 files changed

+193
-58
lines changed

6 files changed

+193
-58
lines changed

cloudshell/cp/vcenter/flows/connectivity_flow.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
is_set_action,
1919
)
2020

21-
from cloudshell.cp.vcenter.exceptions import BaseVCenterException
2221
from cloudshell.cp.vcenter.handlers.dc_handler import DcHandler
2322
from cloudshell.cp.vcenter.handlers.managed_entity_handler import ManagedEntityNotFound
2423
from cloudshell.cp.vcenter.handlers.network_handler import (
@@ -65,15 +64,6 @@
6564
switch_lock = LockHandler()
6665

6766

68-
class DvSwitchNameEmpty(BaseVCenterException):
69-
def __init__(self):
70-
msg = (
71-
"For connectivity actions you have to specify default DvSwitch name in the "
72-
"resource or in every VLAN service"
73-
)
74-
super().__init__(msg)
75-
76-
7767
@define(slots=False)
7868
class VCenterConnectivityFlow(AbcCloudProviderConnectivityFlow):
7969
_si: SiHandler
@@ -105,11 +95,9 @@ def _holding_network(self) -> NetworkHandler | DVPortGroupHandler:
10595
def validate_actions(
10696
self, actions: Collection[VcenterConnectivityActionModel]
10797
) -> None:
108-
for net_settings in map(self._get_network_settings, actions):
109-
without_switch = not net_settings.switch_name
110-
new_network = not net_settings.existed
111-
if without_switch and new_network:
112-
raise DvSwitchNameEmpty
98+
# if switch name not specified in VLAN service or in resource config
99+
# converter would raise an exception
100+
_ = [self._get_network_settings(action) for action in actions]
113101

114102
def pre_connectivity(
115103
self,

cloudshell/cp/vcenter/utils/connectivity_helpers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040
PORT_GROUP_NAME_PATTERN = re.compile(rf"{QS_NAME_PREFIX}_.+_VLAN")
4141

4242

43+
class DvSwitchNameEmpty(BaseVCenterException):
44+
def __init__(self):
45+
msg = (
46+
"For connectivity actions you have to specify default DvSwitch name in the "
47+
"resource or in every VLAN service"
48+
)
49+
super().__init__(msg)
50+
51+
4352
@define
4453
class PgCanNotBeRemoved(BaseVCenterException):
4554
name: str
@@ -222,6 +231,8 @@ def convert(
222231
if name := (old_name := get_existed_port_group_name(action)):
223232
existed = True
224233
else:
234+
if not switch:
235+
raise DvSwitchNameEmpty
225236
existed = False
226237
old_name = generate_port_group_name(switch, vlan_id, port_mode)
227238
name = generate_port_group_name_v2(

tests/conftest.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
from unittest.mock import MagicMock, Mock, patch
33

44
import pytest
5+
from pyVmomi import vim, vmodl
56

67
from cloudshell.cp.core.cancellation_manager import CancellationContextManager
78
from cloudshell.cp.core.request_actions import GetVMDetailsRequestActions
9+
from cloudshell.cp.core.reservation_info import ReservationInfo
810
from cloudshell.shell.core.driver_context import (
911
AppContext,
1012
ConnectivityContext,
@@ -18,10 +20,12 @@
1820
from cloudshell.cp.vcenter.constants import SHELL_NAME, STATIC_SHELL_NAME
1921
from cloudshell.cp.vcenter.handlers.cluster_handler import ClusterHandler
2022
from cloudshell.cp.vcenter.handlers.dc_handler import DcHandler
23+
from cloudshell.cp.vcenter.handlers.managed_entity_handler import ManagedEntityHandler
2124
from cloudshell.cp.vcenter.handlers.si_handler import SiHandler
2225
from cloudshell.cp.vcenter.handlers.vm_handler import VmHandler
2326
from cloudshell.cp.vcenter.models.deployed_app import StaticVCenterDeployedApp
2427
from cloudshell.cp.vcenter.resource_config import VCenterResourceConfig
28+
from cloudshell.cp.vcenter.utils.network_watcher import NetworkWatcher
2529

2630

2731
@pytest.fixture()
@@ -83,6 +87,11 @@ def reservation_context_details() -> ReservationContextDetails:
8387
)
8488

8589

90+
@pytest.fixture
91+
def reservation_info(reservation_context_details):
92+
return ReservationInfo._from_reservation_context(reservation_context_details)
93+
94+
8695
@pytest.fixture()
8796
def resource_command_context(
8897
connectivity_context, resource_context_details, reservation_context_details
@@ -122,7 +131,7 @@ def resource_conf(resource_command_context, cs_api) -> VCenterResourceConfig:
122131
promiscuous_mode = "true"
123132
forged_transmits = "true"
124133
mac_address_changes = "false"
125-
enable_tags = "true"
134+
enable_tags = "false"
126135

127136
a_name = VCenterResourceConfig.ATTR_NAMES
128137
get_full_a_name = lambda n: f"{SHELL_NAME}.{n}" # noqa: E731
@@ -151,7 +160,14 @@ def resource_conf(resource_command_context, cs_api) -> VCenterResourceConfig:
151160
get_full_a_name(a_name.enable_tags): enable_tags,
152161
}
153162
)
154-
conf = VCenterResourceConfig.from_context(resource_command_context, cs_api)
163+
164+
class Cfg(VCenterResourceConfig):
165+
__dict__ = {}
166+
167+
def __setattr__(self, key, value):
168+
object.__setattr__(self, key, value)
169+
170+
conf = Cfg.from_context(resource_command_context, cs_api)
155171

156172
return conf
157173

@@ -311,3 +327,42 @@ def static_deployed_app(cs_api) -> StaticVCenterDeployedApp:
311327
GetVMDetailsRequestActions.register_deployment_path(StaticVCenterDeployedApp)
312328
actions = GetVMDetailsRequestActions.from_request(requests, cs_api)
313329
return actions.deployed_apps[0]
330+
331+
332+
@pytest.fixture()
333+
def object_spec(monkeypatch):
334+
m = Mock()
335+
monkeypatch.setattr(vmodl.query.PropertyCollector, "ObjectSpec", m)
336+
return m
337+
338+
339+
@pytest.fixture()
340+
def filter_spec(monkeypatch):
341+
m = Mock()
342+
monkeypatch.setattr(vmodl.query.PropertyCollector, "FilterSpec", m)
343+
return m
344+
345+
346+
@pytest.fixture()
347+
def property_collector(si):
348+
m = Mock()
349+
si.get_vc_obj().content.propertyCollector.CreatePropertyCollector.return_value = m
350+
# no updates
351+
m.WaitForUpdatesEx.side_effect = [None]
352+
return m
353+
354+
355+
@pytest.fixture()
356+
def container(si):
357+
vc_container = Mock(spec=vim.Datacenter)
358+
vc_container.name = "Datacenter"
359+
return ManagedEntityHandler(vc_container, si)
360+
361+
362+
@pytest.fixture()
363+
def network_watcher(si, container, object_spec, filter_spec, property_collector):
364+
# add ability to modify class attributes
365+
class N(NetworkWatcher):
366+
__dict__ = {}
367+
368+
return N(si, container)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
5+
import pytest
6+
7+
from cloudshell.shell.flows.connectivity.parse_request_service import (
8+
ParseConnectivityRequestService,
9+
)
10+
11+
from cloudshell.cp.vcenter.flows.connectivity_flow import VCenterConnectivityFlow
12+
from cloudshell.cp.vcenter.models.connectivity_action_model import (
13+
VcenterConnectivityActionModel,
14+
)
15+
from cloudshell.cp.vcenter.utils.connectivity_helpers import DvSwitchNameEmpty
16+
17+
logger = logging.getLogger(__name__)
18+
19+
20+
ACTION_DICT = {
21+
"connectionId": "96582265-2728-43aa-bc97-cefb2457ca44",
22+
"connectionParams": {
23+
"vlanId": "11",
24+
"mode": "Access",
25+
"vlanServiceAttributes": [
26+
{
27+
"attributeName": "QnQ",
28+
"attributeValue": "False",
29+
"type": "vlanServiceAttribute",
30+
},
31+
{
32+
"attributeName": "CTag",
33+
"attributeValue": "",
34+
"type": "vlanServiceAttribute",
35+
},
36+
{
37+
"attributeName": "VLAN ID",
38+
"attributeValue": "11",
39+
"type": "vlanServiceAttribute",
40+
},
41+
{
42+
"attributeName": "Virtual Network",
43+
"attributeValue": "",
44+
"type": "vlanServiceAttribute",
45+
},
46+
],
47+
"type": "setVlanParameter",
48+
},
49+
"connectorAttributes": [
50+
{
51+
"attributeName": "Interface",
52+
"attributeValue": "mac address",
53+
"type": "connectorAttribute",
54+
},
55+
],
56+
"actionTarget": {
57+
"fullName": "centos",
58+
"fullAddress": "full address",
59+
"type": "actionTarget",
60+
},
61+
"customActionAttributes": [
62+
{
63+
"attributeName": "VM_UUID",
64+
"attributeValue": "vm_uid",
65+
"type": "customAttribute",
66+
},
67+
{
68+
"attributeName": "Vnic Name",
69+
"attributeValue": "vnic",
70+
"type": "customAttribute",
71+
},
72+
],
73+
"actionId": "96582265-2728-43aa-bc97-cefb2457ca44_0900c4b5-0f90-42e3-b495",
74+
"type": "setVlan",
75+
}
76+
77+
78+
@pytest.fixture
79+
def parse_connectivity_service():
80+
return ParseConnectivityRequestService(
81+
is_vlan_range_supported=True, is_multi_vlan_supported=True
82+
)
83+
84+
85+
@pytest.fixture
86+
def flow(
87+
si, parse_connectivity_service, resource_conf, reservation_info, dc, network_watcher
88+
):
89+
return VCenterConnectivityFlow(
90+
parse_connectivity_service, si, resource_conf, reservation_info
91+
)
92+
93+
94+
@pytest.fixture
95+
def set_action():
96+
return VcenterConnectivityActionModel.model_validate(ACTION_DICT)
97+
98+
99+
def test_validate_actions(flow, set_action):
100+
flow.validate_actions([set_action])
101+
102+
103+
def test_validate_actions_without_switch(flow, set_action, resource_conf):
104+
resource_conf.default_dv_switch = None
105+
with pytest.raises(DvSwitchNameEmpty):
106+
flow.validate_actions([set_action])
107+
108+
109+
def test_validate_actions_switch_in_vlan_service(flow, set_action, resource_conf):
110+
resource_conf.default_dv_switch = None
111+
set_action.connection_params.vlan_service_attrs.switch_name = "switch"
112+
flow.validate_actions([set_action])
113+
114+
115+
def test_validate_actions_switch_is_empty_but_we_use_user_created_network(
116+
flow, set_action, resource_conf
117+
):
118+
resource_conf.default_dv_switch = None
119+
set_action.connection_params.vlan_service_attrs.existing_network = "network"
120+
flow.validate_actions([set_action])

tests/cp/vcenter/flows/test_save_restore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def test_save(flow, vm, dc_handler, resource_conf):
9999
vm_uuid = vm.uuid
100100
action_id = "action id"
101101
action = _get_save_action(vm_uuid, "Inherited", action_id)
102-
resource_conf.__dict__["behavior_during_save"] = "Power Off"
102+
resource_conf.behavior_during_save = "Power Off"
103103
cloned_vm_name = f"Clone of {vm.name}"
104104
cloned_vm = Mock(name=cloned_vm_name, path=f"folder/{cloned_vm_name}", uuid="uuid")
105105
cloned_vm.name = cloned_vm_name

tests/cp/vcenter/utils/test_network_watcher.py

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,16 @@
55
from unittest.mock import Mock
66

77
import pytest
8-
from pyVmomi import vim, vmodl
8+
from pyVmomi import vim
99

10-
from cloudshell.cp.vcenter.handlers.managed_entity_handler import ManagedEntityHandler
1110
from cloudshell.cp.vcenter.handlers.network_handler import (
1211
NetworkHandler,
1312
NetworkNotFound,
1413
)
15-
from cloudshell.cp.vcenter.utils.network_watcher import NetworkWatcher
1614

1715
logger = logging.getLogger(__name__)
1816

1917

20-
@pytest.fixture()
21-
def object_spec(monkeypatch):
22-
m = Mock()
23-
monkeypatch.setattr(vmodl.query.PropertyCollector, "ObjectSpec", m)
24-
yield m
25-
26-
27-
@pytest.fixture()
28-
def filter_spec(monkeypatch):
29-
m = Mock()
30-
monkeypatch.setattr(vmodl.query.PropertyCollector, "FilterSpec", m)
31-
yield m
32-
33-
34-
@pytest.fixture()
35-
def property_collector(si):
36-
m = Mock()
37-
si.get_vc_obj().content.propertyCollector.CreatePropertyCollector.return_value = m
38-
yield m
39-
40-
41-
@pytest.fixture()
42-
def container(si):
43-
vc_container = Mock(spec=vim.Datacenter)
44-
vc_container.name = "Datacenter"
45-
return ManagedEntityHandler(vc_container, si)
46-
47-
48-
@pytest.fixture()
49-
def network_watcher(si, container, object_spec, filter_spec, property_collector):
50-
# add ability to modify class attributes
51-
class N(NetworkWatcher):
52-
__dict__ = {}
53-
54-
return N(si, container)
55-
56-
5718
@pytest.fixture()
5819
def update_network_do_nothing(monkeypatch, network_watcher):
5920
m = Mock()

0 commit comments

Comments
 (0)