Skip to content

Commit 3176c3a

Browse files
committed
NE: more unit tests and UI optimization
1 parent 46acb9d commit 3176c3a

File tree

8 files changed

+308
-268
lines changed

8 files changed

+308
-268
lines changed

api/src/test/java/com/cloud/network/NetworkTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import static org.junit.Assert.assertFalse;
2626
import static org.junit.Assert.assertNotNull;
27+
import static org.junit.Assert.assertNull;
2728
import static org.junit.Assert.assertTrue;
2829

2930

@@ -53,4 +54,20 @@ public void testProviderContains() {
5354
Network.Provider transientProviderNew = Network.Provider.createTransientProvider("NetworkExtension");
5455
assertTrue("List should contain the new transient provider with same name", providers.contains(transientProviderNew));
5556
}
57+
58+
@Test
59+
public void testCustomActionServiceLookup() {
60+
Network.Service customAction = Network.Service.getService("CustomAction");
61+
assertNotNull("CustomAction service should be available", customAction);
62+
assertTrue("CustomAction should be part of the supported services list",
63+
Network.Service.listAllServices().contains(customAction));
64+
}
65+
66+
@Test
67+
public void testTransientProviderIsNotGloballyRegistered() {
68+
Network.Provider transientProvider = Network.Provider.createTransientProvider("TransientOnly");
69+
assertNotNull(transientProvider);
70+
assertNull("Transient provider should not be retrievable from the global registry",
71+
Network.Provider.getProvider("TransientOnly"));
72+
}
5673
}

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4966,7 +4966,7 @@ public void unmanageNics(VirtualMachineProfile vm) {
49664966

49674967
@Override
49684968
public void expungeLbVmRefs(List<Long> vmIds, Long batchSize) {
4969-
if (CollectionUtils.isEmpty(getNetworkElementsIncludingExtensions()) || CollectionUtils.isEmpty(vmIds)) {
4969+
if (CollectionUtils.isEmpty(vmIds)) {
49704970
return;
49714971
}
49724972
for (NetworkElement element : getNetworkElementsIncludingExtensions()) {

framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import static org.mockito.Mockito.times;
4141
import static org.mockito.Mockito.verify;
4242
import static org.mockito.Mockito.when;
43+
import static org.mockito.Mockito.withSettings;
4344

4445
import java.io.File;
4546
import java.security.InvalidParameterException;
@@ -136,6 +137,8 @@
136137
import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
137138
import com.cloud.network.dao.PhysicalNetworkVO;
138139
import com.cloud.network.element.NetworkElement;
140+
import com.cloud.network.vpc.Vpc;
141+
import com.cloud.network.vpc.dao.VpcServiceMapDao;
139142
import org.apache.cloudstack.extension.NetworkCustomActionProvider;
140143
import com.cloud.org.Cluster;
141144
import com.cloud.serializer.GsonHelper;
@@ -207,6 +210,8 @@ public class ExtensionsManagerImplTest {
207210
@Mock
208211
private NetworkServiceMapDao networkServiceMapDao;
209212
@Mock
213+
private VpcServiceMapDao vpcServiceMapDao;
214+
@Mock
210215
private NetworkModel networkModel;
211216

212217
@Mock
@@ -1830,6 +1835,231 @@ public void runCustomAction_CheckAccessThrowsException() throws Exception {
18301835
}
18311836
}
18321837

1838+
@Test
1839+
public void runNetworkCustomAction_NoProviderFound_ReturnsFailureResponse() {
1840+
Network network = mock(Network.class);
1841+
when(network.getId()).thenReturn(11L);
1842+
1843+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1844+
when(actionVO.getId()).thenReturn(10L);
1845+
when(actionVO.getUuid()).thenReturn("action-uuid");
1846+
when(actionVO.getName()).thenReturn("dump-config");
1847+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(10L))
1848+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1849+
1850+
ExtensionVO extensionVO = mock(ExtensionVO.class);
1851+
1852+
CustomActionResultResponse response = extensionsManager.runNetworkCustomAction(
1853+
network, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Network, Collections.emptyMap());
1854+
1855+
assertFalse(response.getSuccess());
1856+
assertEquals("No network service provider found for this network", response.getResult().get(ApiConstants.DETAILS));
1857+
}
1858+
1859+
@Test
1860+
public void runNetworkCustomAction_ProviderElementMissing_ReturnsFailureResponse() {
1861+
Network network = mock(Network.class);
1862+
when(network.getId()).thenReturn(12L);
1863+
when(networkServiceMapDao.getProviderForServiceInNetwork(12L, Network.Service.CustomAction)).thenReturn("ExtProvider");
1864+
when(networkModel.getElementImplementingProvider("ExtProvider")).thenReturn(null);
1865+
1866+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1867+
when(actionVO.getId()).thenReturn(11L);
1868+
when(actionVO.getUuid()).thenReturn("action-uuid");
1869+
when(actionVO.getName()).thenReturn("dump-config");
1870+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(11L))
1871+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1872+
1873+
ExtensionVO extensionVO = mock(ExtensionVO.class);
1874+
1875+
CustomActionResultResponse response = extensionsManager.runNetworkCustomAction(
1876+
network, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Network, Collections.emptyMap());
1877+
1878+
assertFalse(response.getSuccess());
1879+
assertEquals("No network element found for provider: ExtProvider", response.getResult().get(ApiConstants.DETAILS));
1880+
}
1881+
1882+
@Test
1883+
public void runNetworkCustomAction_ProviderCannotHandle_ReturnsFailureResponse() {
1884+
Network network = mock(Network.class);
1885+
when(network.getId()).thenReturn(13L);
1886+
when(networkServiceMapDao.getProviderForServiceInNetwork(13L, Network.Service.CustomAction)).thenReturn("ExtProvider");
1887+
1888+
NetworkElement element = mock(NetworkElement.class, withSettings().extraInterfaces(NetworkCustomActionProvider.class));
1889+
NetworkCustomActionProvider provider = (NetworkCustomActionProvider) element;
1890+
when(networkModel.getElementImplementingProvider("ExtProvider")).thenReturn(element);
1891+
when(provider.canHandleCustomAction(network)).thenReturn(false);
1892+
1893+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1894+
when(actionVO.getId()).thenReturn(12L);
1895+
when(actionVO.getUuid()).thenReturn("action-uuid");
1896+
when(actionVO.getName()).thenReturn("dump-config");
1897+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(12L))
1898+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1899+
1900+
ExtensionVO extensionVO = mock(ExtensionVO.class);
1901+
1902+
CustomActionResultResponse response = extensionsManager.runNetworkCustomAction(
1903+
network, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Network, Collections.emptyMap());
1904+
1905+
assertFalse(response.getSuccess());
1906+
assertTrue(response.getResult().get(ApiConstants.DETAILS).contains("cannot handle custom action"));
1907+
}
1908+
1909+
@Test
1910+
public void runNetworkCustomAction_ProviderDoesNotImplementCustomAction_ReturnsFailureResponse() {
1911+
Network network = mock(Network.class);
1912+
when(network.getId()).thenReturn(131L);
1913+
when(networkServiceMapDao.getProviderForServiceInNetwork(131L, Network.Service.CustomAction)).thenReturn("ExtProvider");
1914+
1915+
NetworkElement element = mock(NetworkElement.class);
1916+
when(networkModel.getElementImplementingProvider("ExtProvider")).thenReturn(element);
1917+
1918+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1919+
when(actionVO.getId()).thenReturn(121L);
1920+
when(actionVO.getUuid()).thenReturn("action-uuid");
1921+
when(actionVO.getName()).thenReturn("dump-config");
1922+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(121L))
1923+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1924+
1925+
ExtensionVO extensionVO = mock(ExtensionVO.class);
1926+
1927+
CustomActionResultResponse response = extensionsManager.runNetworkCustomAction(
1928+
network, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Network, Collections.emptyMap());
1929+
1930+
assertFalse(response.getSuccess());
1931+
assertTrue(response.getResult().get(ApiConstants.DETAILS).contains("does not support custom actions"));
1932+
}
1933+
1934+
@Test
1935+
public void runNetworkCustomAction_SuccessfulExecution_ReturnsSuccessResponse() {
1936+
Network network = mock(Network.class);
1937+
when(network.getId()).thenReturn(14L);
1938+
when(networkServiceMapDao.getProviderForServiceInNetwork(14L, Network.Service.CustomAction)).thenReturn("ExtProvider");
1939+
1940+
NetworkElement element = mock(NetworkElement.class, withSettings().extraInterfaces(NetworkCustomActionProvider.class));
1941+
NetworkCustomActionProvider provider = (NetworkCustomActionProvider) element;
1942+
when(networkModel.getElementImplementingProvider("ExtProvider")).thenReturn(element);
1943+
when(provider.canHandleCustomAction(network)).thenReturn(true);
1944+
when(provider.runCustomAction(eq(network), eq("dump-config"), any())).thenReturn("dump-output");
1945+
1946+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1947+
when(actionVO.getId()).thenReturn(13L);
1948+
when(actionVO.getUuid()).thenReturn("action-uuid");
1949+
when(actionVO.getName()).thenReturn("dump-config");
1950+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(13L))
1951+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1952+
1953+
ExtensionVO extensionVO = mock(ExtensionVO.class);
1954+
1955+
CustomActionResultResponse response = extensionsManager.runNetworkCustomAction(
1956+
network, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Network, Collections.emptyMap());
1957+
1958+
assertTrue(response.getSuccess());
1959+
assertEquals("dump-output", response.getResult().get(ApiConstants.DETAILS));
1960+
}
1961+
1962+
@Test
1963+
public void runVpcCustomAction_ProviderNotCustomActionProvider_ReturnsFailureResponse() {
1964+
Vpc vpc = mock(Vpc.class);
1965+
when(vpc.getId()).thenReturn(21L);
1966+
when(vpcServiceMapDao.getProviderForServiceInVpc(21L, Network.Service.CustomAction)).thenReturn("VpcProvider");
1967+
1968+
NetworkElement element = mock(NetworkElement.class);
1969+
when(networkModel.getElementImplementingProvider("VpcProvider")).thenReturn(element);
1970+
1971+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1972+
when(actionVO.getId()).thenReturn(20L);
1973+
when(actionVO.getUuid()).thenReturn("action-uuid");
1974+
when(actionVO.getName()).thenReturn("dump-config");
1975+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(20L))
1976+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1977+
1978+
ExtensionVO extensionVO = mock(ExtensionVO.class);
1979+
1980+
CustomActionResultResponse response = extensionsManager.runVpcCustomAction(
1981+
vpc, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Vpc, Collections.emptyMap());
1982+
1983+
assertFalse(response.getSuccess());
1984+
assertTrue(response.getResult().get(ApiConstants.DETAILS).contains("does not support custom actions"));
1985+
}
1986+
1987+
@Test
1988+
public void runVpcCustomAction_NoProviderFound_ReturnsFailureResponse() {
1989+
Vpc vpc = mock(Vpc.class);
1990+
when(vpc.getId()).thenReturn(211L);
1991+
1992+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
1993+
when(actionVO.getId()).thenReturn(201L);
1994+
when(actionVO.getUuid()).thenReturn("action-uuid");
1995+
when(actionVO.getName()).thenReturn("dump-config");
1996+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(201L))
1997+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
1998+
1999+
ExtensionVO extensionVO = mock(ExtensionVO.class);
2000+
2001+
CustomActionResultResponse response = extensionsManager.runVpcCustomAction(
2002+
vpc, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Vpc, Collections.emptyMap());
2003+
2004+
assertFalse(response.getSuccess());
2005+
assertEquals("No VPC service provider found for this VPC", response.getResult().get(ApiConstants.DETAILS));
2006+
}
2007+
2008+
@Test
2009+
public void runVpcCustomAction_ProviderCannotHandleVpc_ReturnsFailureResponse() {
2010+
Vpc vpc = mock(Vpc.class);
2011+
when(vpc.getId()).thenReturn(212L);
2012+
when(vpcServiceMapDao.getProviderForServiceInVpc(212L, Network.Service.CustomAction)).thenReturn("VpcProvider");
2013+
2014+
NetworkElement element = mock(NetworkElement.class, withSettings().extraInterfaces(NetworkCustomActionProvider.class));
2015+
NetworkCustomActionProvider provider = (NetworkCustomActionProvider) element;
2016+
when(networkModel.getElementImplementingProvider("VpcProvider")).thenReturn(element);
2017+
when(provider.canHandleVpcCustomAction(vpc)).thenReturn(false);
2018+
2019+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
2020+
when(actionVO.getId()).thenReturn(202L);
2021+
when(actionVO.getUuid()).thenReturn("action-uuid");
2022+
when(actionVO.getName()).thenReturn("dump-config");
2023+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(202L))
2024+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
2025+
2026+
ExtensionVO extensionVO = mock(ExtensionVO.class);
2027+
2028+
CustomActionResultResponse response = extensionsManager.runVpcCustomAction(
2029+
vpc, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Vpc, Collections.emptyMap());
2030+
2031+
assertFalse(response.getSuccess());
2032+
assertTrue(response.getResult().get(ApiConstants.DETAILS).contains("cannot handle custom action"));
2033+
}
2034+
2035+
@Test
2036+
public void runVpcCustomAction_SuccessfulExecution_ReturnsSuccessResponse() {
2037+
Vpc vpc = mock(Vpc.class);
2038+
when(vpc.getId()).thenReturn(22L);
2039+
when(vpcServiceMapDao.getProviderForServiceInVpc(22L, Network.Service.CustomAction)).thenReturn("VpcProvider");
2040+
2041+
NetworkElement element = mock(NetworkElement.class, withSettings().extraInterfaces(NetworkCustomActionProvider.class));
2042+
NetworkCustomActionProvider provider = (NetworkCustomActionProvider) element;
2043+
when(networkModel.getElementImplementingProvider("VpcProvider")).thenReturn(element);
2044+
when(provider.canHandleVpcCustomAction(vpc)).thenReturn(true);
2045+
when(provider.runCustomAction(eq(vpc), eq("dump-config"), any())).thenReturn("vpc-dump-output");
2046+
2047+
ExtensionCustomActionVO actionVO = mock(ExtensionCustomActionVO.class);
2048+
when(actionVO.getId()).thenReturn(21L);
2049+
when(actionVO.getUuid()).thenReturn("action-uuid");
2050+
when(actionVO.getName()).thenReturn("dump-config");
2051+
when(extensionCustomActionDetailsDao.listDetailsKeyPairsWithVisibility(21L))
2052+
.thenReturn(new Pair<>(new HashMap<>(), new HashMap<>()));
2053+
2054+
ExtensionVO extensionVO = mock(ExtensionVO.class);
2055+
2056+
CustomActionResultResponse response = extensionsManager.runVpcCustomAction(
2057+
vpc, actionVO, extensionVO, ExtensionCustomAction.ResourceType.Vpc, Collections.emptyMap());
2058+
2059+
assertTrue(response.getSuccess());
2060+
assertEquals("vpc-dump-output", response.getResult().get(ApiConstants.DETAILS));
2061+
}
2062+
18332063
@Test
18342064
public void createCustomActionResponse_SetsBasicFields() {
18352065
ExtensionCustomAction action = mock(ExtensionCustomAction.class);

test/integration/smoke/test_network_extension_namespace.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2839,4 +2839,3 @@ def _mk_action(name, parameters=[]):
28392839
self._teardown_extension()
28402840
except Exception:
28412841
pass
2842-

ui/src/views/extension/AddCustomAction.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export default {
169169
data () {
170170
return {
171171
roleTypes: [],
172-
resourceTypeOptions: ['VirtualMachine', 'Network'],
172+
resourceTypeOptions: ['VirtualMachine', 'Network', 'Vpc'],
173173
loading: false
174174
}
175175
},
@@ -204,13 +204,13 @@ export default {
204204
updateResourceTypeByExtension (selectedExtension) {
205205
const type = selectedExtension?.type
206206
if (type === 'NetworkOrchestrator') {
207-
this.resourceTypeOptions = ['Network']
207+
this.resourceTypeOptions = ['Network', 'Vpc']
208208
this.form.resourcetype = 'Network'
209209
} else if (type === 'Orchestrator') {
210210
this.resourceTypeOptions = ['VirtualMachine']
211211
this.form.resourcetype = 'VirtualMachine'
212212
} else {
213-
this.resourceTypeOptions = ['VirtualMachine', 'Network']
213+
this.resourceTypeOptions = ['VirtualMachine', 'Network', 'Vpc']
214214
if (!this.form.resourcetype) {
215215
this.form.resourcetype = 'VirtualMachine'
216216
}

ui/src/views/extension/ExtensionResourcesTab.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
<template v-if="column.key === 'actions'">
3737
<span style="margin-right: 5px">
3838
<tooltip-button
39+
v-if="'updateRegisteredExtension' in $store.getters.apis"
3940
:tooltip="$t('label.action.update.extension.resource')"
4041
type="default"
4142
icon="edit-outlined"

0 commit comments

Comments
 (0)