CORD-1801: [2/2] Fix dependencies involving controller objects + Unit
test updates and additions
Change-Id: I12565db9e3a5f1fe2d376aa4e763330826771bea
(cherry picked from commit 2263db14363b4825168c34e1c9e42b69a569e7d6)
diff --git a/lib/xos-genx/xosgenx/targets/model-deps.xtarget b/lib/xos-genx/xosgenx/targets/model-deps.xtarget
index 74a8647..7beccfd 100644
--- a/lib/xos-genx/xosgenx/targets/model-deps.xtarget
+++ b/lib/xos-genx/xosgenx/targets/model-deps.xtarget
@@ -1,9 +1,22 @@
-{ {%- for model in proto.messages %} "{{ model.name }}": [
- {% for l in xproto_base_links(model, proto.message_table) + model.links -%}
- {% if "Controller" + l.peer.name in proto.message_names -%}
- ["Controller{{ l.peer.name }}", "{{ l.src_port }}", "{{ xproto_camel_to_underscore(l.peer.name).lower() }}"],
- {% endif %}
- ["{{ l.peer.name }}", "{{ l.src_port }}", ""]{% if not loop.last %},{% endif %}
+{ {%- for model in proto.messages %}
+ {% if model.name not in ["Controller", "XOSBase"] %}
+ "{{ model.name }}": [
+ {% set controller_model_name = "Controller" + model.name %}
+ {% set controller_model_name_plural = "Controller" + xproto_pluralize(model) %}
+ {% set controller_models = (proto.message_table[controller_model_name], proto.message_table[controller_model_name_plural]) %}
+ {% set controller_model = xproto_first_non_empty(controller_models) %}
+ {% if controller_model %}
+ {% set controller_links = xproto_base_links(controller_model, proto.message_table) + controller_model.links %}
+ {% for cl in controller_links %}
+ {% set _=cl.__setitem__("model_name", cl.options.model) %}
{% endfor %}
- ]{{ "," if not loop.last }}{% endfor %}
+ {% set controller_backlinks = controller_links | selectattr("model_name", "equalto", model.name) %}
+ {% for backlink in controller_backlinks %}
+ ["{{ controller_model.name }}", "{{ backlink.dst_port }}", "{{ backlink.src_port }}"],
+ {% endfor %}
+ {% endif %}
+ {% for l in xproto_base_links(model, proto.message_table) + model.links -%}
+ ["{{ l.peer.name }}", "{{ l.src_port }}", "{{ l.dst_port }}"]{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]{{ "," if not loop.last }}{% endif %}{% endfor %}
}
diff --git a/xos/synchronizers/new_base/event_loop.py b/xos/synchronizers/new_base/event_loop.py
index 9a87b56..2919d26 100644
--- a/xos/synchronizers/new_base/event_loop.py
+++ b/xos/synchronizers/new_base/event_loop.py
@@ -16,7 +16,6 @@
import sys
import threading
import json
-import pdb
import pprint
import traceback
from collections import defaultdict
@@ -24,7 +23,6 @@
from networkx.algorithms.dag import topological_sort
from datetime import datetime
-#from multistructlog import create_logger
from xosconfig import Config
from synchronizers.new_base.steps import *
from syncstep import InnocuousException, DeferredException, SyncStep
@@ -56,6 +54,8 @@
# set_driver() below.
DRIVER = NoOpDriver()
+DIRECT_EDGE = 1
+PROXY_EDGE = 2
def set_driver(x):
global DRIVER
@@ -403,6 +403,28 @@
returns False.
"""
+ def same_object(self, o1, o2):
+ if not o1 or not o2:
+ return False, None
+
+ try:
+ o1_lst = (o for o in o1.all())
+ edge_type = PROXY_EDGE
+ except (AttributeError, TypeError):
+ o1_lst = [o1]
+ edge_type = DIRECT_EDGE
+
+ try:
+ found = next(obj for obj in o1_lst if obj.leaf_model_name ==
+ o2.leaf_model_name and obj.pk == o2.pk)
+ except AttributeError as e:
+ self.log.exception('Compared objects could not be identified', e=e)
+ raise e
+ except StopIteration:
+ found = False
+
+ return found, edge_type
+
def concrete_path_exists(self, o1, o2):
try:
m1 = o1.leaf_model_name
@@ -410,7 +432,7 @@
except AttributeError:
# One of the nodes is not in the dependency graph
# No dependency
- return False
+ return False, None
# FIXME: Dynamic dependency check
G = self.model_dependency_graph[False]
diff --git a/xos/synchronizers/new_base/tests/model-deps-onos.yaml b/xos/synchronizers/new_base/tests/model-deps-onos.yaml
deleted file mode 100644
index a459052..0000000
--- a/xos/synchronizers/new_base/tests/model-deps-onos.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-# 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.
-
-
-{
- "ONOSApp": [
- ["ONOSService", "", ""]
- ]
- }
diff --git a/xos/synchronizers/new_base/tests/model-deps.yaml b/xos/synchronizers/new_base/tests/model-deps.yaml
deleted file mode 100644
index 0c92522..0000000
--- a/xos/synchronizers/new_base/tests/model-deps.yaml
+++ /dev/null
@@ -1,378 +0,0 @@
-
-# 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.
-
-
-{
- "XOSBase": [
-
- ],
- "User": [
- "ControllerSite",
-
- "Site",
- "ControllerDashboardView",
-
- "DashboardView"
-
- ],
- "Privilege": [
-
- ],
- "AddressPool": [
-
- "Service"
-
- ],
- "Controller": [
-
- "Deployment"
-
- ],
- "ControllerDashboardView": [
-
- "Controller",
- "ControllerDashboardView",
-
- "DashboardView"
-
- ],
- "ControllerImages": [
-
- "Image",
-
- "Controller"
-
- ],
- "ControllerNetwork": [
- "ControllerNetwork",
-
- "Network",
-
- "Controller"
-
- ],
- "ControllerRole": [
-
- ],
- "ControllerSite": [
- "ControllerSite",
-
- "Site",
-
- "Controller"
-
- ],
- "ControllerPrivilege": [
-
- "Controller",
- "ControllerPrivilege",
-
- "Privilege"
-
- ],
- "ControllerSitePrivilege": [
-
- "Controller",
- "ControllerSitePrivilege",
-
- "SitePrivilege"
-
- ],
- "ControllerSlice": [
-
- "Controller",
- "ControllerSlice",
-
- "Slice"
-
- ],
- "ControllerSlicePrivilege": [
-
- "Controller",
- "ControllerSlicePrivilege",
-
- "SlicePrivilege"
-
- ],
- "ControllerUser": [
- "ControllerUser",
-
- "User",
-
- "Controller"
-
- ],
- "DashboardView": [
-
- "Controller",
-
- "Deployment"
-
- ],
- "Deployment": [
-
- ],
- "DeploymentPrivilege": [
- "ControllerUser",
-
- "User",
-
- "Deployment",
-
- "DeploymentRole"
-
- ],
- "DeploymentRole": [
-
- ],
- "Diag": [
-
- ],
- "Flavor": [
-
- ],
- "Image": [
-
- ],
- "ImageDeployments": [
-
- "Image",
-
- "Deployment"
-
- ],
- "Instance": [
-
- "Image",
- "ControllerUser",
-
- "User",
- "ControllerSlice",
-
- "Slice",
-
- "Deployment",
-
- "Node",
-
- "Flavor",
-
- "Instance"
-
- ],
- "Network": [
-
- "NetworkTemplate",
- "ControllerSlice",
-
- "Slice",
- "ControllerSlice",
-
- "Slice",
- "ControllerSlice",
-
- "Slice",
-
- "Instance"
-
- ],
- "NetworkParameter": [
-
- "NetworkParameterType"
-
- ],
- "NetworkParameterType": [
-
- ],
- "NetworkSlice": [
- "ControllerNetwork",
-
- "Network",
- "ControllerSlice",
-
- "Slice"
-
- ],
- "NetworkTemplate": [
-
- ],
- "Node": [
-
- "SiteDeployment"
-
- ],
- "NodeLabel": [
-
- "Node"
-
- ],
- "Port": [
- "ControllerNetwork",
-
- "Network",
-
- "Instance"
-
- ],
- "Role": [
-
- ],
- "Service": [
-
- ],
- "ServiceAttribute": [
-
- "Service"
-
- ],
- "ServiceDependency": [
-
- "Service",
-
- "Service"
-
- ],
- "ServiceMonitoringAgentInfo": [
-
- "Service"
-
- ],
- "ServicePrivilege": [
- "ControllerUser",
-
- "User",
-
- "Service",
-
- "ServiceRole"
-
- ],
- "ServiceRole": [
-
- ],
- "Site": [
-
- "Deployment"
-
- ],
- "SiteDeployment": [
- "ControllerSite",
-
- "Site",
-
- "Deployment",
-
- "Controller"
-
- ],
- "SitePrivilege": [
- "ControllerUser",
-
- "User",
- "ControllerSite",
-
- "Site",
-
- "SiteRole"
-
- ],
- "SiteRole": [
-
- ],
- "Slice": [
- "ControllerSite",
-
- "Site",
-
- "Service",
- "ControllerUser",
-
- "User",
-
- "Flavor",
-
- "Image",
-
- "Node"
-
- ],
- "SlicePrivilege": [
- "ControllerUser",
-
- "User",
- "ControllerSlice",
-
- "Slice",
-
- "SliceRole"
-
- ],
- "SliceRole": [
-
- ],
- "Tag": [
-
- "Service"
-
- ],
- "InterfaceType": [
-
- ],
- "ServiceInterface": [
-
- "Service",
-
- "InterfaceType"
-
- ],
- "ServiceInstance": [
-
- "Service"
-
- ],
- "ServiceInstanceLink": [
-
- "ServiceInstance",
-
- "ServiceInterface",
-
- "ServiceInstance",
-
- "Service",
- "ControllerNetwork",
-
- "Network"
-
- ],
- "ServiceInstanceAttribute": [
-
- "ServiceInstance"
-
- ],
- "TenantWithContainer": [
-
- "Instance",
- "ControllerUser",
-
- "User"
-
- ],
- "XOS": [
-
- ],
- "XOSGuiExtension": [
-
- ]
-}
diff --git a/xos/synchronizers/new_base/tests/steps/mock_modelaccessor.py b/xos/synchronizers/new_base/tests/steps/mock_modelaccessor.py
index c390327..ef038cc 100644
--- a/xos/synchronizers/new_base/tests/steps/mock_modelaccessor.py
+++ b/xos/synchronizers/new_base/tests/steps/mock_modelaccessor.py
@@ -12,36 +12,42 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
from mock import Mock
import random
+def mock_enumerator(items):
+ e = lambda:None
+ e.all = lambda:items
+ return e
+
class Object:
objects = Mock()
def __init__(self, **kwargs):
- for (k,v) in kwargs.items():
- setattr(self,k,v)
-
setattr(self, 'save', Mock())
setattr(self, 'delete', Mock())
setattr(self, 'backend_code', 0)
setattr(self, 'id', 98052)
+ setattr(self, 'pk', random.randint(0, 1<<30))
+
+ for (k,v) in kwargs.items():
+ setattr(self,k,v)
+
def tologdict(self):
return {}
class ONOSService(Object):
- pass
+ leaf_model_name = 'ONOSService'
-class ONOSTenant(Object):
- pass
+class ONOSApp(Object):
+ leaf_model_name = 'ONOSApp'
class ModelAccessor:
def check_db_connection_ok(self):
return True
def fetch_pending(self, model, deleted = False):
- num = random.randint(1,5)
+ num = random.randint(1, 5)
object_list = []
for i in range(num):
@@ -61,6 +67,13 @@
model_accessor = ModelAccessor()
+class ObjectSet(object):
+ def __init__(self, objects):
+ self.objects = objects
+
+ def all(self):
+ return self.objects
+
#####
# DO NOT MODIFY THE CLASSES BELOW. THEY ARE AUTOGENERATED.
#
@@ -84,6 +97,7 @@
leaf_model_name = None
leaf_model_name = "XOSBase"
+
class User(Object):
email = None
username = "Something"
diff --git a/xos/synchronizers/new_base/tests/steps/sync_controller_networks.py b/xos/synchronizers/new_base/tests/steps/sync_controller_networks.py
index f4f31f2..793b87d 100644
--- a/xos/synchronizers/new_base/tests/steps/sync_controller_networks.py
+++ b/xos/synchronizers/new_base/tests/steps/sync_controller_networks.py
@@ -55,17 +55,7 @@
pass
def map_delete_inputs(self, controller_network):
- network_name = controller_network.network.name
- subnet_name = '%s-%d'%(network_name,controller_network.pk)
- cidr = controller_network.subnet
- network_fields = {'endpoint':controller_network.controller.auth_url,
- 'admin_user':slice.creator.email, # XXX: FIXME
- 'admin_project':slice.name, # XXX: FIXME
- 'admin_password':slice.creator.remote_password,
- 'name':network_name,
- 'subnet_name':subnet_name,
- 'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name),
- 'cidr':cidr,
+ network_fields = {'endpoint':None,
'delete':True
}
diff --git a/xos/synchronizers/new_base/tests/test_config.yaml b/xos/synchronizers/new_base/tests/test_config.yaml
index e5ec0d3..5dc99fe 100644
--- a/xos/synchronizers/new_base/tests/test_config.yaml
+++ b/xos/synchronizers/new_base/tests/test_config.yaml
@@ -20,5 +20,13 @@
kind: testframework
logging:
version: 1
-dependency_graph: "model-deps.yaml"
+ handlers:
+ console:
+ class: logging.StreamHandler
+ loggers:
+ '':
+ handlers:
+ - console
+ level: DEBUG
+dependency_graph: "tests/model-deps"
steps_dir: "tests/steps"
diff --git a/xos/synchronizers/new_base/tests/test_config_onos.yaml b/xos/synchronizers/new_base/tests/test_config_onos.yaml
index 8862ff6..c3eb562 100644
--- a/xos/synchronizers/new_base/tests/test_config_onos.yaml
+++ b/xos/synchronizers/new_base/tests/test_config_onos.yaml
@@ -20,5 +20,5 @@
kind: testframework
logging:
version: 1
-dependency_graph: "tests/model-deps-onos.yaml"
+dependency_graph: "tests/model-deps-onos"
steps_dir: "tests/steps"
diff --git a/xos/synchronizers/new_base/tests/test_load.py b/xos/synchronizers/new_base/tests/test_load.py
index 575732b..8f75f03 100644
--- a/xos/synchronizers/new_base/tests/test_load.py
+++ b/xos/synchronizers/new_base/tests/test_load.py
@@ -56,14 +56,14 @@
graph = self.synchronizer.model_dependency_graph
self.assertTrue(graph[False].has_edge('Instance','Slice'))
self.assertTrue(graph[True].has_edge('Slice','Instance'))
- self.assertTrue(graph[False].has_edge('Instance','ControllerSlice'))
- self.assertTrue(graph[True].has_edge('ControllerSlice','Instance'))
+ self.assertTrue(graph[False].has_edge('Slice','ControllerSlice'))
+ self.assertTrue(graph[True].has_edge('ControllerSlice','Slice'))
def test_load_dep_accessors(self):
self.synchronizer.load_dependency_graph()
graph = self.synchronizer.model_dependency_graph
- self.assertDictContainsSubset({'src_accessor': 'slice'}, graph[False]['Instance']['ControllerSlice'])
- self.assertDictContainsSubset({'src_accessor': 'slice', 'dst_accessor': 'slice'}, graph[True]['ControllerSlice']['Instance'])
+ self.assertDictContainsSubset({'src_accessor': 'controllerslices'}, graph[False]['Slice']['ControllerSlice'])
+ self.assertDictContainsSubset({'src_accessor': 'slice', 'dst_accessor': 'controllerslices'}, graph[True]['Slice']['ControllerSlice'])
def test_load_sync_steps(self):
self.synchronizer.load_sync_steps()
diff --git a/xos/synchronizers/new_base/tests/test_payload.py b/xos/synchronizers/new_base/tests/test_payload.py
index 909c739..15c5874 100644
--- a/xos/synchronizers/new_base/tests/test_payload.py
+++ b/xos/synchronizers/new_base/tests/test_payload.py
@@ -37,6 +37,9 @@
import steps.sync_instances
import steps.sync_controller_slices
+from multistructlog import create_logger
+
+log = create_logger()
ANSIBLE_FILE='/tmp/payload_test'
@@ -62,7 +65,7 @@
o.name = "Sisi Pascal"
o.synchronizer_step = steps.sync_instances.SyncInstances()
- self.synchronizer.delete_record(o)
+ self.synchronizer.delete_record(o, log)
a = get_ansible_output()
self.assertDictContainsSubset({'delete':True, 'name':o.name}, a)
@@ -75,7 +78,7 @@
o.name = "Sisi Pascal"
o.synchronizer_step = steps.sync_instances.SyncInstances()
- self.synchronizer.sync_record(o)
+ self.synchronizer.sync_record(o, log)
a = get_ansible_output()
self.assertDictContainsSubset({'delete':False, 'name':o.name}, a)
@@ -162,8 +165,9 @@
self.synchronizer.external_dependencies = []
cohorts = self.synchronizer.compute_dependent_cohorts(pending_objects, False)
+ flat_objects = [item for cohort in cohorts for item in cohort]
- self.assertEqual(len(cohorts), len(pending_objects) - 1)
+ self.assertEqual(set(flat_objects), set(pending_objects))
@mock.patch("steps.sync_instances.syncstep.run_template",side_effect=run_fake_ansible_template)
@mock.patch("event_loop.model_accessor")
@@ -178,7 +182,8 @@
cohorts = self.synchronizer.compute_dependent_cohorts(pending_objects, False)
- self.assertEqual(len(cohorts), len(pending_objects))
+ flat_objects = [item for cohort in cohorts for item in cohort]
+ self.assertEqual(set(flat_objects), set(pending_objects))
# These cannot be None, but for documentation purposes
self.assertIsNotNone(any_cn)
diff --git a/xos/synchronizers/new_base/tests/test_run.py b/xos/synchronizers/new_base/tests/test_run.py
index 1ca1a2c..3a52449 100644
--- a/xos/synchronizers/new_base/tests/test_run.py
+++ b/xos/synchronizers/new_base/tests/test_run.py
@@ -54,8 +54,14 @@
steps_dir = Config.get("steps_dir")
self.steps = b.load_sync_step_modules(steps_dir)
self.synchronizer = event_loop.XOSObserver(self.steps)
- os.remove('/tmp/sync_ports')
- os.remove('/tmp/delete_ports')
+ try:
+ os.remove('/tmp/sync_ports')
+ except OSError:
+ pass
+ try:
+ os.remove('/tmp/delete_ports')
+ except OSError:
+ pass
@mock.patch("steps.sync_instances.syncstep.run_template",side_effect=run_fake_ansible_template)
@mock.patch("event_loop.model_accessor")
diff --git a/xos/synchronizers/new_base/tests/test_scheduler.py b/xos/synchronizers/new_base/tests/test_scheduler.py
index 8bf5652..db1698a 100644
--- a/xos/synchronizers/new_base/tests/test_scheduler.py
+++ b/xos/synchronizers/new_base/tests/test_scheduler.py
@@ -47,10 +47,53 @@
self.steps = b.load_sync_step_modules(steps_dir)
self.synchronizer = event_loop.XOSObserver(self.steps)
+ def test_same_object_trivial(self):
+ s = Slice(pk=4)
+ t = Slice(pk=4)
+ same, t = self.synchronizer.same_object(s, t)
+ self.assertTrue(same)
+ self.assertEqual(t, event_loop.DIRECT_EDGE)
+
+ def test_same_object_trivial2(self):
+ s = Slice(pk=4)
+ t = Slice(pk=5)
+ same, t = self.synchronizer.same_object(s, t)
+ self.assertFalse(same)
+
+ def test_same_object_lst(self):
+ s = Slice(pk=5)
+ t = ControllerSlice(slice=s)
+ u = ControllerSlice(slice=s)
+
+ s.controllerslices = mock_enumerator([t,u])
+
+ same, et = self.synchronizer.same_object(s.controllerslices, u)
+ self.assertTrue(same)
+ self.assertEqual(et, event_loop.PROXY_EDGE)
+
+ same, et = self.synchronizer.same_object(s.controllerslices, t)
+
+ self.assertTrue(same)
+ self.assertEqual(et, event_loop.PROXY_EDGE)
+
+ def test_same_object_lst_dc(self):
+ r = Slice(pk=4)
+ s = Slice(pk=5)
+ t = ControllerSlice(slice=r)
+ u = ControllerSlice(slice=s)
+
+ s.controllerslices = mock_enumerator([u])
+
+ same, et = self.synchronizer.same_object(s.controllerslices, t)
+ self.assertFalse(same)
+
+ same, et = self.synchronizer.same_object(s.controllerslices, u)
+ self.assertTrue(same)
+
def test_concrete_path_no_model_path(self):
p = Port()
n = NetworkParameter()
- verdict = self.synchronizer.concrete_path_exists(p, n)
+ verdict,_ = self.synchronizer.concrete_path_exists(p, n)
self.assertFalse(verdict)
def test_concrete_no_object_path_adjacent(self):
@@ -58,7 +101,7 @@
s1 = Slice()
s2 = Slice()
p.slice = s2
- verdict = self.synchronizer.concrete_path_exists(p, s1)
+ verdict,_ = self.synchronizer.concrete_path_exists(p, s1)
self.assertFalse(verdict)
@@ -66,9 +109,10 @@
p = Instance()
s = Slice()
p.slice = s
- verdict = self.synchronizer.concrete_path_exists(p, s)
+ verdict, edge_type = self.synchronizer.concrete_path_exists(p, s)
self.assertTrue(verdict)
+ self.assertEqual(edge_type, event_loop.DIRECT_EDGE)
def test_concrete_object_controller_path_adjacent(self):
p = Instance()
@@ -80,15 +124,20 @@
p.slice = s1
q.slice = s2
cs.slice = s1
+ s1.controllerslices = mock_enumerator([cs])
+ s2.controllerslices = mock_enumerator([])
- verdict1 = self.synchronizer.concrete_path_exists(p, cs)
- verdict2 = self.synchronizer.concrete_path_exists(q, cs)
- verdict3 = self.synchronizer.concrete_path_exists(p, cs2)
+
+ verdict1, edge_type1 = self.synchronizer.concrete_path_exists(p, cs)
+ verdict2, _ = self.synchronizer.concrete_path_exists(q, cs)
+ verdict3, _ = self.synchronizer.concrete_path_exists(p, cs2)
self.assertTrue(verdict1)
self.assertFalse(verdict2)
self.assertFalse(verdict3)
+ self.assertEqual(edge_type1, event_loop.PROXY_EDGE)
+
def test_concrete_object_controller_path_distant(self):
p = Instance()
s = Slice()
@@ -112,18 +161,27 @@
def test_concrete_no_object_path_distant(self):
p = Instance()
s = Slice()
+ s.controllerslice=mock_enumerator([])
+
t = Site()
+ t.controllersite=mock_enumerator([])
+
ct = ControllerSite()
ct.site = Site()
p.slice = s
s.site = t
- verdict = self.synchronizer.concrete_path_exists(p, ct)
- self.assertTrue(verdict)
+
+ verdict, _ = self.synchronizer.concrete_path_exists(p, ct)
+ self.assertFalse(verdict)
def test_cohorting_independent(self):
i = Image()
+
p = Slice()
c = Instance()
+ c.slice = None
+ c.image = None
+
cohorts = self.synchronizer.compute_dependent_cohorts([i,p,c], False)
self.assertEqual(len(cohorts), 3)
@@ -147,6 +205,7 @@
cs = ControllerSlice()
s = Slice()
cs.slice = s
+ s.controllerslices = mock_enumerator([cs])
c.slice = s
cohorts = self.synchronizer.compute_dependent_cohorts([i,p,c,s,cs], False)
@@ -156,6 +215,23 @@
self.assertGreater(big_cohort.index(cs), big_cohort.index(s))
self.assertIn([p], cohorts)
+ def test_cohorting_related_multi_delete(self):
+ i = Image()
+ p = Port()
+ c = Instance()
+ c.image = i
+ cs = ControllerSlice()
+ s = Slice()
+ cs.slice = s
+ c.slice = s
+
+ cohorts = self.synchronizer.compute_dependent_cohorts([i,p,c,s,cs], True)
+
+ big_cohort = max(cohorts, key=len)
+ self.assertGreater(big_cohort.index(i), big_cohort.index(c))
+ self.assertGreater(big_cohort.index(s), big_cohort.index(cs))
+ self.assertIn([p], cohorts)
+
def test_cohorting_related_delete(self):
i = Image()
p = Port()
diff --git a/xos/synchronizers/new_base/tests/test_services.py b/xos/synchronizers/new_base/tests/test_services.py
index d3b67c7..418b36e 100644
--- a/xos/synchronizers/new_base/tests/test_services.py
+++ b/xos/synchronizers/new_base/tests/test_services.py
@@ -42,14 +42,20 @@
self.synchronizer = event_loop.XOSObserver(self.steps)
def test_service_models(self):
- o = ONOSApp()
- t = ONOSService()
+ a = ONOSApp()
+ s = ONOSService()
- cohorts = self.synchronizer.compute_dependent_cohorts([o,t], False)
- self.assertIn([t,o], cohorts)
+ cohorts = self.synchronizer.compute_dependent_cohorts([a,s], False)
+ self.assertIn([s,a], cohorts)
- cohorts = self.synchronizer.compute_dependent_cohorts([t,o], False)
- self.assertIn([t,o], cohorts)
+ cohorts = self.synchronizer.compute_dependent_cohorts([s,a], False)
+ self.assertIn([s,a], cohorts)
+
+ cohorts = self.synchronizer.compute_dependent_cohorts([a,s], True)
+ self.assertIn([a,s], cohorts)
+
+ cohorts = self.synchronizer.compute_dependent_cohorts([s,a], True)
+ self.assertIn([a,s], cohorts)
if __name__ == '__main__':
unittest.main()