Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 5afe904

Browse files
author
Michael Smith
committed
Add more test coverage. Bug fix on EP delete.
1 parent 9c475f8 commit 5afe904

2 files changed

Lines changed: 131 additions & 57 deletions

File tree

applications/multisite/multisite.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,15 @@ def get_remote_sites_using_epg(self, epg):
136136
def _add_endpoint_subnet(self, tenant, endpoint, remote_site,
137137
remote_contracts={}):
138138
network = OutsideNetwork(endpoint.name)
139-
network.network = endpoint.ip + '/32'
140-
if remote_site in remote_contracts:
141-
for contract in remote_contracts[remote_site]['provides']:
142-
network.provide(Contract(contract, tenant))
143-
for contract in remote_contracts[remote_site]['consumes']:
144-
network.consume(Contract(contract, tenant))
139+
if endpoint.is_deleted():
140+
network.mark_as_deleted()
141+
else:
142+
network.network = endpoint.ip + '/32'
143+
if remote_site in remote_contracts:
144+
for contract in remote_contracts[remote_site]['provides']:
145+
network.provide(Contract(contract, tenant))
146+
for contract in remote_contracts[remote_site]['consumes']:
147+
network.consume(Contract(contract, tenant))
145148
outside_epg_entries = self._local_site.outside_db.get_outside_epg_entries(tenant.name,
146149
remote_site)
147150
if len(outside_epg_entries) == 0:

applications/multisite/multisite_test.py

Lines changed: 122 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,46 @@
2424
"""
2525
sys.exit(0)
2626

27-
# driver.get(SITE1_URL)
28-
# driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't')
29-
# driver.get(SITE2_URL)
30-
# driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't')
31-
3227
class TestBasicExport(unittest.TestCase):
28+
@staticmethod
29+
def _start_server(db_filename, server_port):
30+
os.environ["MULTISITE_DATABASE_FILE"] = db_filename
31+
subprocess.call(["rm", "-rf", db_filename])
32+
subprocess.Popen(["python", "multisite-gui.py", "--port", server_port, "--test"])
33+
time.sleep(1)
34+
3335
@classmethod
3436
def setUpClass(cls):
35-
36-
3737
# Run the multisite tool for first site
38-
site1_db_filename = "site1_db.sqlite"
39-
os.environ["MULTISITE_DATABASE_FILE"] = site1_db_filename
40-
subprocess.call(["rm", "-rf", site1_db_filename])
41-
subprocess.Popen(["python", "multisite-gui.py", "--port", "5000", "--test"])
42-
time.sleep(1)
38+
cls._start_server('site1_db.sqlite', '5000')
4339

4440
# Run the multisite tool for second site
45-
site2_db_filename = "site2_db.sqlite"
46-
os.environ["MULTISITE_DATABASE_FILE"] = site2_db_filename
47-
subprocess.call(["rm", "-rf", site2_db_filename])
48-
subprocess.Popen(["python", "multisite-gui.py", "--port", "5001", "--test"])
49-
time.sleep(1)
41+
cls._start_server('site2_db.sqlite', '5001')
5042

43+
# Start the browser
5144
cls.driver = webdriver.Firefox()
5245

46+
def _enter_credentials(self, driver, site_name, ip_address, user_name, password, local):
47+
# Enter the Site 1 credentials
48+
typing = [('site_name', site_name),
49+
('ip_address', ip_address),
50+
('user_name', user_name),
51+
('password', password)]
52+
for (field, data) in typing:
53+
input_elem = driver.find_element_by_id(field)
54+
input_elem.send_keys(data)
55+
if local:
56+
input_elem = driver.find_element_by_id('local')
57+
input_elem.click()
58+
59+
def _login_session(self, url, login, password):
60+
session = Session(url, login, password)
61+
resp = session.login()
62+
self.assertTrue(resp.ok)
63+
return session
64+
65+
5366
def setup_site(self, url, site1_local=True):
54-
# driver = webdriver.Firefox()
55-
# driver.maximize_window()
5667
driver = self.__class__.driver
5768
driver.find_element_by_tag_name('body').send_keys(Keys.COMMAND + 't')
5869

@@ -65,32 +76,16 @@ def setup_site(self, url, site1_local=True):
6576
driver.find_element_by_link_text('Create').click()
6677

6778
# Enter the Site 1 credentials
68-
typing = [('site_name', 'Site1'),
69-
('ip_address', SITE1_IP),
70-
('user_name', SITE1_LOGIN),
71-
('password', SITE1_PASSWORD)]
72-
for (field, data) in typing:
73-
input_elem = driver.find_element_by_id(field)
74-
input_elem.send_keys(data)
75-
if site1_local:
76-
input_elem = driver.find_element_by_id('local')
77-
input_elem.click()
79+
self._enter_credentials(driver, 'Site1', SITE1_IP, SITE1_LOGIN,
80+
SITE1_PASSWORD, site1_local)
7881

7982
# Save the credentials
8083
input_elem = driver.find_element_by_name('_add_another')
8184
input_elem.click()
8285

8386
# Enter the Site 2 credentials
84-
typing = [('site_name', 'Site2'),
85-
('ip_address', SITE2_IP),
86-
('user_name', SITE2_LOGIN),
87-
('password', SITE2_PASSWORD)]
88-
for (field, data) in typing:
89-
input_elem = driver.find_element_by_id(field)
90-
input_elem.send_keys(data)
91-
if not site1_local:
92-
input_elem = driver.find_element_by_id('local')
93-
input_elem.click()
87+
self._enter_credentials(driver, 'Site2', SITE2_IP, SITE2_LOGIN,
88+
SITE2_PASSWORD, not site1_local)
9489

9590
# Save the credentials
9691
input_elem = driver.find_element_by_name('_add_another')
@@ -102,12 +97,35 @@ def setup_site(self, url, site1_local=True):
10297

10398
# TODO: go to the site screen and verify that both sites are present
10499

100+
def _verify_l3extsubnet(self, session, tenant_name, mac, ip, present=True):
101+
class_query_url = ("/api/mo/uni/tn-%s.json?query-target=subtree&"
102+
"target-subtree-class=l3extSubnet" % tenant_name)
103+
resp = session.get(class_query_url)
104+
data = resp.json()['imdata']
105+
if present:
106+
self.assertTrue(len(data))
107+
found = False
108+
for subnet in data:
109+
self.assertTrue('l3extSubnet' in subnet)
110+
dn = subnet['l3extSubnet']['attributes']['dn']
111+
if mac in dn and ip in dn:
112+
found = True
113+
if present:
114+
self.assertTrue(found)
115+
else:
116+
self.assertFalse(found)
117+
118+
105119
def test_01_site1(self):
106120
self.setup_site('http://127.0.0.1:5000', site1_local=True)
107121

108122
def test_02_site2(self):
109123
self.setup_site('http://127.0.0.1:5001', site1_local=False)
110124

125+
# TODO test removing a site
126+
# TODO test adding the same site twice
127+
# TODO
128+
111129
def test_03_export_contract(self):
112130
driver = self.__class__.driver
113131
# Switch to the site 1 tool
@@ -135,18 +153,14 @@ def test_03_export_contract(self):
135153

136154
time.sleep(1)
137155
# Verify that the export to the other APIC was successful
138-
session = Session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
139-
resp = session.login()
140-
self.assertTrue(resp.ok)
156+
session = self._login_session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
141157
tenants = Tenant.get_deep(session, names=['multisite'], limit_to=['fvTenant', 'vzBrCP'])
142158
self.assertTrue(len(tenants) > 0)
143159
multisite_tenant = tenants[0]
144160
self.assertIsNotNone(multisite_tenant.get_child(Contract, 'Site1:mysql-contract'))
145161

146162
def test_04_consume_exported_contract(self):
147-
session = Session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
148-
resp = session.login()
149-
self.assertTrue(resp.ok)
163+
session = self._login_session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
150164

151165
# Create the Tenant
152166
tenant = Tenant('multisite')
@@ -172,9 +186,7 @@ def test_04_consume_exported_contract(self):
172186
self.assertTrue(epg.does_consume(contract))
173187

174188
def test_05_add_consuming_static_endpoint(self):
175-
session = Session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
176-
resp = session.login()
177-
self.assertTrue(resp.ok)
189+
session = self._login_session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
178190

179191
tenant = Tenant('multisite')
180192
app = AppProfile('my-demo-app', tenant)
@@ -207,10 +219,15 @@ def test_05_add_consuming_static_endpoint(self):
207219
ep = epg.get_child(Endpoint, '00:33:33:33:33:33')
208220
self.assertIsNotNone(ep)
209221

222+
session = self._login_session(SITE1_URL, SITE1_LOGIN, SITE1_PASSWORD)
223+
self._verify_l3extsubnet(session,
224+
tenant_name='multisite',
225+
mac='00:33:33:33:33:33',
226+
ip='2.3.4.5/32',
227+
present=True)
228+
210229
def test_06_add_providing_static_endpoint(self):
211-
session = Session(SITE1_URL, SITE1_LOGIN, SITE1_PASSWORD)
212-
resp = session.login()
213-
self.assertTrue(resp.ok)
230+
session = self._login_session(SITE1_URL, SITE1_LOGIN, SITE1_PASSWORD)
214231

215232
tenant = Tenant('multisite')
216233
app = AppProfile('my-demo-app', tenant)
@@ -246,6 +263,60 @@ def test_06_add_providing_static_endpoint(self):
246263
ep = epg.get_child(Endpoint, '00:44:44:44:44:44')
247264
self.assertIsNotNone(ep)
248265

266+
session = self._login_session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
267+
self._verify_l3extsubnet(session,
268+
tenant_name = 'multisite',
269+
mac='00:44:44:44:44:44',
270+
ip='7.8.9.10/32',
271+
present=True)
272+
273+
def test_07_remove_consuming_static_endpoint(self):
274+
session = self._login_session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
275+
276+
tenant = Tenant('multisite')
277+
app = AppProfile('my-demo-app', tenant)
278+
web_epg = EPG('web-frontend', app)
279+
280+
# Create the Endpoint
281+
ep = Endpoint('00:33:33:33:33:33', web_epg)
282+
ep.mac = '00:33:33:33:33:33'
283+
ep.ip = '2.3.4.5'
284+
285+
intf = Interface('eth', '1', '101', '1', '38')
286+
# Create a VLAN interface and attach to the physical interface
287+
vlan_intf = L2Interface('vlan-5', 'vlan', '5')
288+
vlan_intf.attach(intf)
289+
# Attach the EPG to the VLAN interface
290+
web_epg.attach(vlan_intf)
291+
# Assign Endpoint to the L2Interface
292+
ep.attach(vlan_intf)
293+
294+
# Mark the Endpoint as deleted
295+
ep.mark_as_deleted()
296+
297+
print 'Pushing json to tenant', tenant.get_json()
298+
resp = tenant.push_to_apic(session)
299+
self.assertTrue(resp.ok)
300+
301+
# Verify that the Endpoint has been removed
302+
time.sleep(1)
303+
tenants = Tenant.get_deep(session, names=['multisite'])
304+
multisite_tenant = tenants[0]
305+
app = multisite_tenant.get_child(AppProfile, 'my-demo-app')
306+
self.assertIsNotNone(app)
307+
epg = app.get_child(EPG, 'web-frontend')
308+
self.assertIsNotNone(epg)
309+
ep = epg.get_child(Endpoint, '00:33:33:33:33:33')
310+
self.assertIsNone(ep)
311+
312+
# Verify that the l3extSubnet has been removed from the other site
313+
session = self._login_session(SITE2_URL, SITE2_LOGIN, SITE2_PASSWORD)
314+
self._verify_l3extsubnet(session,
315+
tenant_name = 'multisite',
316+
mac='00:33:33:33:33:33',
317+
ip='2.3.4.5/32',
318+
present=False)
319+
249320
@classmethod
250321
def tearDownClass(cls):
251322
driver = cls.driver

0 commit comments

Comments
 (0)