CORD-1920: Fix synchronizer unit tests + 6 new tests + enable
parallelization of Instance and ControllerNetwork
Change-Id: Ied77aeb1c6e7bdf6c5cb5dc252fd8a998bca79de
diff --git a/xos/synchronizers/new_base/event_loop.py b/xos/synchronizers/new_base/event_loop.py
index a64283a..98ce2a3 100644
--- a/xos/synchronizers/new_base/event_loop.py
+++ b/xos/synchronizers/new_base/event_loop.py
@@ -489,6 +489,8 @@
"""
if dst_objects==[]:
+ # Workaround for ORM not returning linked deleted
+ # objects
if o2.deleted:
return True, edge_type
else:
@@ -499,9 +501,22 @@
else:
dst_object = dst_objects[0]
except AttributeError as e:
- if sa!='fake_accessor':
- self.log.debug(
- 'Could not check object dependencies, making conservative choice', src_object=src_object, sa=sa, o1=o1, o2=o2)
+ # Fake accessors are links between models that have a dependency
+ # but that do not have a path in the data model, such as Instance and ControllerNetowrk.
+ # They are implemented as a workaround until a true dependency path is created in
+ # the data model.
+ if sa.startswith('fake_accessor'):
+ if sa.endswith('deletion'):
+ if o2.deleted:
+ return True, edge_type
+ else:
+ break
+ else:
+ return True, edge_type
+
+ self.log.debug(
+ 'Could not check object dependencies, making conservative choice', src_object=src_object, sa=sa, o1=o1, o2=o2)
+
return True, edge_type
src_object = dst_object
@@ -509,9 +524,12 @@
if not src_object:
break
- verdict, edge_type = self.same_object(src_object, o2)
+ verdict, leaf_edge_type = self.same_object(src_object, o2)
if verdict:
- return verdict, edge_type
+ if edge_type == PROXY_EDGE:
+ leaf_edge_type = PROXY_EDGE
+
+ return verdict, leaf_edge_type
# Otherwise try other paths
diff --git a/xos/synchronizers/new_base/tests/model-deps b/xos/synchronizers/new_base/tests/model-deps
index 75a60e0..66b3abb 100644
--- a/xos/synchronizers/new_base/tests/model-deps
+++ b/xos/synchronizers/new_base/tests/model-deps
@@ -275,6 +275,8 @@
["Deployment", "deployment", "instance_deployment"],
["Node", "node", "instances"],
["Flavor", "flavor", "instance"],
+ ["ControllerNetwork", "fake_accessor_deletion", "fake_accessor_deletion"],
+ ["ImageDeployments", "fake_accessor", "fake_accessor"],
["Instance", "parent", "instance"]
],
diff --git a/xos/synchronizers/new_base/tests/steps/__init__.py b/xos/synchronizers/new_base/tests/steps/__init__.py
new file mode 100644
index 0000000..d4e8062
--- /dev/null
+++ b/xos/synchronizers/new_base/tests/steps/__init__.py
@@ -0,0 +1,16 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
diff --git a/xos/synchronizers/new_base/tests/test_controller_dependencies.py b/xos/synchronizers/new_base/tests/test_controller_dependencies.py
index f5deb84..268e062 100644
--- a/xos/synchronizers/new_base/tests/test_controller_dependencies.py
+++ b/xos/synchronizers/new_base/tests/test_controller_dependencies.py
@@ -101,6 +101,38 @@
cohorts = self.synchronizer.compute_dependent_cohorts([i, slice, site, csl, csi], False)
self.assertEqual([site, csi, slice, csl, i], cohorts[0])
+ def test_instance_fake_dependency_path(self):
+ i = Instance()
+ id = ImageDeployments()
+ id.deleted = False
+ verdict, edge_type = self.synchronizer.concrete_path_exists(i, id)
+
+ self.assertTrue(verdict)
+
+ def test_instance_fake_deletion_dependency_path_delete(self):
+ i = Instance()
+ cn = ControllerNetwork()
+ cn.deleted = True
+ verdict, edge_type = self.synchronizer.concrete_path_exists(i, cn)
+
+ self.assertTrue(verdict)
+
+ def test_instance_fake_deletion_dependency_path(self):
+ i = Instance()
+ cn = ControllerNetwork()
+ cn.deleted = False
+ verdict, edge_type = self.synchronizer.concrete_path_exists(i, cn)
+
+ self.assertFalse(verdict)
+
+ def test_instance_fake_dependency_path_delete(self):
+ i = Instance()
+ cn = ControllerNetwork()
+ cn.deleted = True
+ verdict, edge_type = self.synchronizer.concrete_path_exists(i, cn)
+
+ self.assertTrue(verdict)
+
def test_multi_controller_path_negative(self):
csl = ControllerSlice()
csi = ControllerSite()
@@ -152,6 +184,7 @@
csl = ControllerSlice()
cn = ControllerNetwork()
site = Site()
+ csi = ControllerSite()
slice = Slice()
slice.site = site
slice.controllerslices = mock_enumerator([])
@@ -179,6 +212,124 @@
self.assertIn([site, slice, i], cohorts)
self.assertIn([csl], cohorts)
self.assertIn([csi], cohorts)
+
+ def test_multiple_service_cohorts(self):
+ csl0 = ControllerSlice()
+ csl0.tag = 0
+ csi0 = ControllerSite()
+ csi0.tag = 0
+ site0 = Site()
+ site0.tag = 0
+ slice0 = Slice()
+ slice0.tag = 0
+ slice0.site = site0
+ slice0.controllerslices = mock_enumerator([csl0])
+ site0.controllersite = mock_enumerator([csi0])
+ site0.tag = 0
+ i0 = Instance()
+ i0.tag = 0
+ i0.slice = slice0
+
+ csl1 = ControllerSlice()
+ csi1 = ControllerSite()
+ site1 = Site()
+ slice1 = Slice()
+ slice1.site = site1
+ slice1.controllerslices = mock_enumerator([csl1])
+ site1.controllersite = mock_enumerator([csi1])
+ i1 = Instance()
+ i1.slice = slice1
+
+ cohorts = self.synchronizer.compute_dependent_cohorts([i0, slice0, site0, csl0, csi0, i1, slice1, site1, csl1, csi1], False)
+
+ self.assertEqual(len(cohorts), 2)
+ self.assertEqual(len(cohorts[0]), len(cohorts[1]))
+
+ def test_multiple_service_cohorts_with_fake_dependency(self):
+ csl0 = ControllerSlice()
+ csl0.tag = 0
+ csi0 = ControllerSite()
+ csi0.tag = 0
+ site0 = Site()
+ site0.tag = 0
+ slice0 = Slice()
+ slice0.tag = 0
+ slice0.site = site0
+ slice0.controllerslices = mock_enumerator([csl0])
+ site0.controllersite = mock_enumerator([csi0])
+ site0.tag = 0
+ i0 = Instance()
+ i0.tag = 0
+ i0.slice = slice0
+ csn0 = ControllerNetwork()
+ csn0.tag = 0
+ n0 = Network()
+ n0.tag = 0
+ n0.controllernetworks = mock_enumerator([csn0])
+ n0.owner = slice0
+
+ csl1 = ControllerSlice()
+ csi1 = ControllerSite()
+ site1 = Site()
+ slice1 = Slice()
+ slice1.site = site1
+ slice1.controllerslices = mock_enumerator([csl1])
+ site1.controllersite = mock_enumerator([csi1])
+ i1 = Instance()
+ i1.slice = slice1
+ csn1 = ControllerNetwork()
+ n1 = Network()
+ n1.controllernetworks = mock_enumerator([csn1])
+ n1.owner = slice1
+
+ cohorts = self.synchronizer.compute_dependent_cohorts([i0, slice0, site0, csl0, csi0, csn0, i1, slice1, site1, csl1, csi1, csn1], False)
+
+ self.assertEqual(len(cohorts), 4)
+ self.assertEqual(len(cohorts[1]), len(cohorts[3]))
+
+
+ def test_multiple_service_cohorts_with_fake_dependency_deletion(self):
+ csl0 = ControllerSlice()
+ csl0.tag = 0
+ csi0 = ControllerSite()
+ csi0.tag = 0
+ site0 = Site()
+ site0.tag = 0
+ slice0 = Slice()
+ slice0.tag = 0
+ slice0.site = site0
+ slice0.controllerslices = mock_enumerator([csl0])
+ site0.controllersite = mock_enumerator([csi0])
+ site0.tag = 0
+ i0 = Instance()
+ i0.tag = 0
+ i0.slice = slice0
+ csn0 = ControllerNetwork()
+ csn0.tag = 0
+ n0 = Network()
+ n0.tag = 0
+ n0.controllernetworks = mock_enumerator([csn0])
+ n0.owner = slice0
+ csn0.deleted = True
+
+ csl1 = ControllerSlice()
+ csi1 = ControllerSite()
+ site1 = Site()
+ slice1 = Slice()
+ slice1.site = site1
+ slice1.controllerslices = mock_enumerator([csl1])
+ site1.controllersite = mock_enumerator([csi1])
+ i1 = Instance()
+ i1.slice = slice1
+ csn1 = ControllerNetwork()
+ n1 = Network()
+ n1.controllernetworks = mock_enumerator([csn1])
+ n1.owner = slice1
+ csn1.deleted = True
+
+ cohorts = self.synchronizer.compute_dependent_cohorts([i0, slice0, site0, csl0, csi0, csn0, i1, slice1, site1, csl1, csi1, csn1], True)
+
+ self.assertEqual(len(cohorts), 1)
if __name__ == '__main__':
unittest.main()