Added strategy ID + Action Plan syncing
In this changeset, I implemented the logic which cancels any audit or action plan whose goal has been re-synced (upon restarting the Decision Engine). Partially Implements: blueprint efficacy-indicator Change-Id: I95d2739eb552d4a7a02c822b11844591008f648e
This commit is contained in:
@@ -13,10 +13,11 @@
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import mock
|
||||
|
||||
import uuid
|
||||
|
||||
from apscheduler.schedulers import background
|
||||
import mock
|
||||
|
||||
from watcher.decision_engine.audit import continuous
|
||||
from watcher.decision_engine.audit import oneshot
|
||||
@@ -30,13 +31,17 @@ from watcher.tests.objects import utils as obj_utils
|
||||
|
||||
|
||||
class TestOneShotAuditHandler(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOneShotAuditHandler, self).setUp()
|
||||
obj_utils.create_test_goal(self.context, id=1, name="dummy")
|
||||
self.strategy = obj_utils.create_test_strategy(
|
||||
self.context, name='dummy')
|
||||
audit_template = obj_utils.create_test_audit_template(
|
||||
self.context)
|
||||
self.context, strategy_id=self.strategy.id)
|
||||
self.audit = obj_utils.create_test_audit(
|
||||
self.context,
|
||||
strategy_id=self.strategy.id,
|
||||
audit_template_id=audit_template.id)
|
||||
|
||||
@mock.patch.object(manager.CollectorManager, "get_cluster_model_collector")
|
||||
@@ -79,11 +84,12 @@ class TestContinuousAuditHandler(base.DbTestCase):
|
||||
obj_utils.create_test_goal(self.context, id=1, name="DUMMY")
|
||||
audit_template = obj_utils.create_test_audit_template(
|
||||
self.context)
|
||||
self.audits = [obj_utils.create_test_audit(
|
||||
self.context,
|
||||
uuid=uuid.uuid4(),
|
||||
audit_template_id=audit_template.id,
|
||||
audit_type=audit_objects.AuditType.CONTINUOUS.value)
|
||||
self.audits = [
|
||||
obj_utils.create_test_audit(
|
||||
self.context,
|
||||
uuid=uuid.uuid4(),
|
||||
audit_template_id=audit_template.id,
|
||||
audit_type=audit_objects.AuditType.CONTINUOUS.value)
|
||||
for i in range(2)]
|
||||
|
||||
@mock.patch.object(background.BackgroundScheduler, 'add_job')
|
||||
|
||||
@@ -81,8 +81,3 @@ class FakeDummy1(FakeGoal):
|
||||
class FakeDummy2(FakeGoal):
|
||||
NAME = "dummy_2"
|
||||
DISPLAY_NAME = "Dummy 2"
|
||||
|
||||
|
||||
class FakeOtherDummy2(FakeGoal):
|
||||
NAME = "dummy_2"
|
||||
DISPLAY_NAME = "Other Dummy 2"
|
||||
|
||||
@@ -59,11 +59,16 @@ class SolutionFakerSingleHyp(object):
|
||||
|
||||
class TestActionScheduling(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestActionScheduling, self).setUp()
|
||||
self.strategy = db_utils.create_test_strategy(name="dummy")
|
||||
self.audit = db_utils.create_test_audit(
|
||||
uuid=utils.generate_uuid(), strategy_id=self.strategy.id)
|
||||
self.default_planner = pbase.DefaultPlanner(mock.Mock())
|
||||
|
||||
def test_schedule_actions(self):
|
||||
default_planner = pbase.DefaultPlanner(mock.Mock())
|
||||
audit = db_utils.create_test_audit(uuid=utils.generate_uuid())
|
||||
solution = dsol.DefaultSolution(
|
||||
goal=mock.Mock(), strategy=mock.Mock())
|
||||
goal=mock.Mock(), strategy=self.strategy)
|
||||
|
||||
parameters = {
|
||||
"source_node": "server1",
|
||||
@@ -74,11 +79,12 @@ class TestActionScheduling(base.DbTestCase):
|
||||
input_parameters=parameters)
|
||||
|
||||
with mock.patch.object(
|
||||
pbase.DefaultPlanner, "create_action",
|
||||
wraps=default_planner.create_action) as m_create_action:
|
||||
default_planner.config.weights = {'migrate': 3}
|
||||
action_plan = default_planner.schedule(self.context,
|
||||
audit.id, solution)
|
||||
pbase.DefaultPlanner, "create_action",
|
||||
wraps=self.default_planner.create_action
|
||||
) as m_create_action:
|
||||
self.default_planner.config.weights = {'migrate': 3}
|
||||
action_plan = self.default_planner.schedule(
|
||||
self.context, self.audit.id, solution)
|
||||
|
||||
self.assertIsNotNone(action_plan.uuid)
|
||||
self.assertEqual(1, m_create_action.call_count)
|
||||
@@ -87,10 +93,8 @@ class TestActionScheduling(base.DbTestCase):
|
||||
self.assertEqual("migrate", actions[0].action_type)
|
||||
|
||||
def test_schedule_two_actions(self):
|
||||
default_planner = pbase.DefaultPlanner(mock.Mock())
|
||||
audit = db_utils.create_test_audit(uuid=utils.generate_uuid())
|
||||
solution = dsol.DefaultSolution(
|
||||
goal=mock.Mock(), strategy=mock.Mock())
|
||||
goal=mock.Mock(), strategy=self.strategy)
|
||||
|
||||
parameters = {
|
||||
"source_node": "server1",
|
||||
@@ -105,11 +109,12 @@ class TestActionScheduling(base.DbTestCase):
|
||||
input_parameters={})
|
||||
|
||||
with mock.patch.object(
|
||||
pbase.DefaultPlanner, "create_action",
|
||||
wraps=default_planner.create_action) as m_create_action:
|
||||
default_planner.config.weights = {'migrate': 3, 'nop': 0}
|
||||
action_plan = default_planner.schedule(self.context,
|
||||
audit.id, solution)
|
||||
pbase.DefaultPlanner, "create_action",
|
||||
wraps=self.default_planner.create_action
|
||||
) as m_create_action:
|
||||
self.default_planner.config.weights = {'migrate': 3, 'nop': 0}
|
||||
action_plan = self.default_planner.schedule(
|
||||
self.context, self.audit.id, solution)
|
||||
self.assertIsNotNone(action_plan.uuid)
|
||||
self.assertEqual(2, m_create_action.call_count)
|
||||
# check order
|
||||
@@ -119,10 +124,8 @@ class TestActionScheduling(base.DbTestCase):
|
||||
self.assertEqual("migrate", actions[1].action_type)
|
||||
|
||||
def test_schedule_actions_with_unknown_action(self):
|
||||
default_planner = pbase.DefaultPlanner(mock.Mock())
|
||||
audit = db_utils.create_test_audit(uuid=utils.generate_uuid())
|
||||
solution = dsol.DefaultSolution(
|
||||
goal=mock.Mock(), strategy=mock.Mock())
|
||||
goal=mock.Mock(), strategy=self.strategy)
|
||||
|
||||
parameters = {
|
||||
"src_uuid_node": "server1",
|
||||
@@ -137,11 +140,12 @@ class TestActionScheduling(base.DbTestCase):
|
||||
input_parameters={})
|
||||
|
||||
with mock.patch.object(
|
||||
pbase.DefaultPlanner, "create_action",
|
||||
wraps=default_planner.create_action) as m_create_action:
|
||||
default_planner.config.weights = {'migrate': 0}
|
||||
self.assertRaises(KeyError, default_planner.schedule,
|
||||
self.context, audit.id, solution)
|
||||
pbase.DefaultPlanner, "create_action",
|
||||
wraps=self.default_planner.create_action
|
||||
) as m_create_action:
|
||||
self.default_planner.config.weights = {'migrate': 0}
|
||||
self.assertRaises(KeyError, self.default_planner.schedule,
|
||||
self.context, self.audit.id, solution)
|
||||
self.assertEqual(2, m_create_action.call_count)
|
||||
|
||||
|
||||
@@ -158,6 +162,7 @@ class TestDefaultPlanner(base.DbTestCase):
|
||||
}
|
||||
|
||||
obj_utils.create_test_audit_template(self.context)
|
||||
self.strategy = obj_utils.create_test_strategy(self.context)
|
||||
|
||||
p = mock.patch.object(db_api.BaseConnection, 'create_action_plan')
|
||||
self.mock_create_action_plan = p.start()
|
||||
@@ -179,14 +184,18 @@ class TestDefaultPlanner(base.DbTestCase):
|
||||
action.create()
|
||||
return action
|
||||
|
||||
def test_schedule_scheduled_empty(self):
|
||||
@mock.patch.object(objects.Strategy, 'get_by_name')
|
||||
def test_schedule_scheduled_empty(self, m_get_by_name):
|
||||
m_get_by_name.return_value = self.strategy
|
||||
audit = db_utils.create_test_audit(uuid=utils.generate_uuid())
|
||||
fake_solution = SolutionFakerSingleHyp.build()
|
||||
action_plan = self.default_planner.schedule(self.context,
|
||||
audit.id, fake_solution)
|
||||
self.assertIsNotNone(action_plan.uuid)
|
||||
|
||||
def test_scheduler_warning_empty_action_plan(self):
|
||||
@mock.patch.object(objects.Strategy, 'get_by_name')
|
||||
def test_scheduler_warning_empty_action_plan(self, m_get_by_name):
|
||||
m_get_by_name.return_value = self.strategy
|
||||
audit = db_utils.create_test_audit(uuid=utils.generate_uuid())
|
||||
fake_solution = SolutionFaker.build()
|
||||
action_plan = self.default_planner.schedule(self.context,
|
||||
|
||||
@@ -44,7 +44,7 @@ class TestStrategyContext(base.DbTestCase):
|
||||
mock_call.return_value = strategies.DummyStrategy(
|
||||
config=mock.Mock())
|
||||
solution = self.strategy_context.execute_strategy(
|
||||
self.audit.uuid, self.context)
|
||||
self.audit, self.context)
|
||||
self.assertIsInstance(solution, default.DefaultSolution)
|
||||
|
||||
@mock.patch.object(manager.CollectorManager, "get_cluster_model_collector",
|
||||
@@ -65,8 +65,7 @@ class TestStrategyContext(base.DbTestCase):
|
||||
uuid=utils.generate_uuid(),
|
||||
)
|
||||
|
||||
solution = self.strategy_context.execute_strategy(
|
||||
audit.uuid, self.context)
|
||||
solution = self.strategy_context.execute_strategy(audit, self.context)
|
||||
|
||||
self.assertEqual(len(solution.actions), 3)
|
||||
|
||||
@@ -92,7 +91,6 @@ class TestStrategyContext(base.DbTestCase):
|
||||
uuid=utils.generate_uuid(),
|
||||
)
|
||||
|
||||
solution = self.strategy_context.execute_strategy(
|
||||
audit.uuid, self.context)
|
||||
solution = self.strategy_context.execute_strategy(audit, self.context)
|
||||
|
||||
self.assertEqual(solution, expected_strategy)
|
||||
|
||||
@@ -21,6 +21,7 @@ from watcher.common import utils
|
||||
from watcher.decision_engine.loading import default
|
||||
from watcher.decision_engine import sync
|
||||
from watcher import objects
|
||||
from watcher.objects import action_plan as ap_objects
|
||||
from watcher.tests.db import base
|
||||
from watcher.tests.decision_engine import fake_goals
|
||||
from watcher.tests.decision_engine import fake_strategies
|
||||
@@ -73,6 +74,27 @@ class TestSyncer(base.DbTestCase):
|
||||
self.addCleanup(p_goals_load.stop)
|
||||
self.addCleanup(p_strategies.stop)
|
||||
|
||||
@staticmethod
|
||||
def _find_created_modified_unmodified_ids(befores, afters):
|
||||
created = {
|
||||
a_item.id: a_item for a_item in afters
|
||||
if a_item.uuid not in (b_item.uuid for b_item in befores)
|
||||
}
|
||||
|
||||
modified = {
|
||||
a_item.id: a_item for a_item in afters
|
||||
if a_item.as_dict() not in (
|
||||
b_items.as_dict() for b_items in befores)
|
||||
}
|
||||
|
||||
unmodified = {
|
||||
a_item.id: a_item for a_item in afters
|
||||
if a_item.as_dict() in (
|
||||
b_items.as_dict() for b_items in befores)
|
||||
}
|
||||
|
||||
return created, modified, unmodified
|
||||
|
||||
@mock.patch.object(objects.Strategy, "soft_delete")
|
||||
@mock.patch.object(objects.Strategy, "save")
|
||||
@mock.patch.object(objects.Strategy, "create")
|
||||
@@ -257,15 +279,18 @@ class TestSyncer(base.DbTestCase):
|
||||
strategy1 = objects.Strategy(
|
||||
self.ctx, id=1, name="strategy_1", uuid=utils.generate_uuid(),
|
||||
display_name="Strategy 1", goal_id=goal1.id)
|
||||
# Should stay unmodified after sync()
|
||||
# Should be modified after sync() because its related goal has been
|
||||
# modified
|
||||
strategy2 = objects.Strategy(
|
||||
self.ctx, id=2, name="strategy_2", uuid=utils.generate_uuid(),
|
||||
display_name="Strategy 2", goal_id=goal2.id)
|
||||
# Should be modified by the sync()
|
||||
# Should be modified after sync() because its strategy name has been
|
||||
# modified
|
||||
strategy3 = objects.Strategy(
|
||||
self.ctx, id=3, name="strategy_3", uuid=utils.generate_uuid(),
|
||||
display_name="Original", goal_id=goal2.id)
|
||||
# Should be modified by the sync()
|
||||
display_name="Original", goal_id=goal1.id)
|
||||
# Should be modified after sync() because both its related goal
|
||||
# and its strategy name have been modified
|
||||
strategy4 = objects.Strategy(
|
||||
self.ctx, id=4, name="strategy_4", uuid=utils.generate_uuid(),
|
||||
display_name="Original", goal_id=goal2.id)
|
||||
@@ -279,18 +304,18 @@ class TestSyncer(base.DbTestCase):
|
||||
|
||||
# Should stay unmodified after sync()
|
||||
audit_template1 = objects.AuditTemplate(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
name="Synced AT1", goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
self.ctx, id=1, name="Synced AT1", uuid=utils.generate_uuid(),
|
||||
goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Should be modified by the sync() because its associated goal
|
||||
# should be modified
|
||||
# has been modified (compared to the defined fake goals)
|
||||
audit_template2 = objects.AuditTemplate(
|
||||
self.ctx, id=2, name="Synced AT2", uuid=utils.generate_uuid(),
|
||||
goal_id=goal2.id, strategy_id=strategy2.id)
|
||||
# Should be modified by the sync() because its associated strategy
|
||||
# should be modified
|
||||
# has been modified (compared to the defined fake strategies)
|
||||
audit_template3 = objects.AuditTemplate(
|
||||
self.ctx, id=3, name="Synced AT3", uuid=utils.generate_uuid(),
|
||||
goal_id=goal2.id, strategy_id=strategy3.id)
|
||||
goal_id=goal1.id, strategy_id=strategy3.id)
|
||||
# Modified because of both because its associated goal and associated
|
||||
# strategy should be modified
|
||||
audit_template4 = objects.AuditTemplate(
|
||||
@@ -301,9 +326,70 @@ class TestSyncer(base.DbTestCase):
|
||||
audit_template3.create()
|
||||
audit_template4.create()
|
||||
|
||||
before_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
# Should stay unmodified after sync()
|
||||
audit1 = objects.Audit(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Should be modified by the sync() because its associated goal
|
||||
# has been modified (compared to the defined fake goals)
|
||||
audit2 = objects.Audit(
|
||||
self.ctx, id=2, uuid=utils.generate_uuid(),
|
||||
goal_id=goal2.id, strategy_id=strategy2.id)
|
||||
# Should be modified by the sync() because its associated strategy
|
||||
# has been modified (compared to the defined fake strategies)
|
||||
audit3 = objects.Audit(
|
||||
self.ctx, id=3, uuid=utils.generate_uuid(),
|
||||
goal_id=goal1.id, strategy_id=strategy3.id)
|
||||
# Modified because of both because its associated goal and associated
|
||||
# strategy should be modified (compared to the defined fake
|
||||
# goals/strategies)
|
||||
audit4 = objects.Audit(
|
||||
self.ctx, id=4, uuid=utils.generate_uuid(),
|
||||
goal_id=goal2.id, strategy_id=strategy4.id)
|
||||
|
||||
audit1.create()
|
||||
audit2.create()
|
||||
audit3.create()
|
||||
audit4.create()
|
||||
|
||||
# Should stay unmodified after sync()
|
||||
action_plan1 = objects.ActionPlan(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
audit_id=audit1.id, strategy_id=strategy1.id,
|
||||
first_action_id=None, state='DOESNOTMATTER',
|
||||
global_efficacy={})
|
||||
# Stale after syncing because the goal of the audit has been modified
|
||||
# (compared to the defined fake goals)
|
||||
action_plan2 = objects.ActionPlan(
|
||||
self.ctx, id=2, uuid=utils.generate_uuid(),
|
||||
audit_id=audit2.id, strategy_id=strategy2.id,
|
||||
first_action_id=None, state='DOESNOTMATTER',
|
||||
global_efficacy={})
|
||||
# Stale after syncing because the strategy has been modified
|
||||
# (compared to the defined fake strategies)
|
||||
action_plan3 = objects.ActionPlan(
|
||||
self.ctx, id=3, uuid=utils.generate_uuid(),
|
||||
audit_id=audit3.id, strategy_id=strategy3.id,
|
||||
first_action_id=None, state='DOESNOTMATTER',
|
||||
global_efficacy={})
|
||||
# Stale after syncing because both the strategy and the related audit
|
||||
# have been modified (compared to the defined fake goals/strategies)
|
||||
action_plan4 = objects.ActionPlan(
|
||||
self.ctx, id=4, uuid=utils.generate_uuid(),
|
||||
audit_id=audit4.id, strategy_id=strategy4.id,
|
||||
first_action_id=None, state='DOESNOTMATTER',
|
||||
global_efficacy={})
|
||||
|
||||
action_plan1.create()
|
||||
action_plan2.create()
|
||||
action_plan3.create()
|
||||
action_plan4.create()
|
||||
|
||||
before_goals = objects.Goal.list(self.ctx)
|
||||
before_strategies = objects.Strategy.list(self.ctx)
|
||||
before_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
before_audits = objects.Audit.list(self.ctx)
|
||||
before_action_plans = objects.ActionPlan.list(self.ctx)
|
||||
|
||||
# ### Action under test ### #
|
||||
|
||||
@@ -314,30 +400,51 @@ class TestSyncer(base.DbTestCase):
|
||||
|
||||
# ### Assertions ### #
|
||||
|
||||
after_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
after_goals = objects.Goal.list(self.ctx)
|
||||
after_strategies = objects.Strategy.list(self.ctx)
|
||||
after_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
after_audits = objects.Audit.list(self.ctx)
|
||||
after_action_plans = objects.ActionPlan.list(self.ctx)
|
||||
|
||||
self.assertEqual(2, len(before_goals))
|
||||
self.assertEqual(4, len(before_strategies))
|
||||
self.assertEqual(4, len(before_audit_templates))
|
||||
self.assertEqual(4, len(before_audits))
|
||||
self.assertEqual(4, len(before_action_plans))
|
||||
self.assertEqual(2, len(after_goals))
|
||||
self.assertEqual(4, len(after_strategies))
|
||||
self.assertEqual(4, len(after_audit_templates))
|
||||
self.assertEqual(4, len(after_audits))
|
||||
self.assertEqual(4, len(after_action_plans))
|
||||
|
||||
self.assertEqual(
|
||||
{"dummy_1", "dummy_2"},
|
||||
set([g.name for g in after_goals]))
|
||||
self.assertEqual(
|
||||
{"strategy_1", "strategy_2", "strategy_3", "strategy_4"},
|
||||
set([s.name for s in after_strategies]))
|
||||
created_goals = {
|
||||
ag.name: ag for ag in after_goals
|
||||
if ag.uuid not in [bg.uuid for bg in before_goals]
|
||||
}
|
||||
created_strategies = {
|
||||
a_s.name: a_s for a_s in after_strategies
|
||||
if a_s.uuid not in [b_s.uuid for b_s in before_strategies]
|
||||
}
|
||||
|
||||
created_goals, modified_goals, unmodified_goals = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_goals, after_goals))
|
||||
|
||||
created_strategies, modified_strategies, unmodified_strategies = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_strategies, after_strategies))
|
||||
|
||||
(created_audit_templates, modified_audit_templates,
|
||||
unmodified_audit_templates) = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_audit_templates, after_audit_templates))
|
||||
|
||||
created_audits, modified_audits, unmodified_audits = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_audits, after_audits))
|
||||
|
||||
(created_action_plans, modified_action_plans,
|
||||
unmodified_action_plans) = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_action_plans, after_action_plans))
|
||||
|
||||
dummy_1_spec = [
|
||||
{'description': 'Dummy indicator', 'name': 'dummy',
|
||||
@@ -351,40 +458,34 @@ class TestSyncer(base.DbTestCase):
|
||||
|
||||
self.assertEqual(1, len(created_goals))
|
||||
self.assertEqual(3, len(created_strategies))
|
||||
|
||||
modified_audit_templates = {
|
||||
a_at.id for a_at in after_audit_templates
|
||||
if a_at.goal_id not in (
|
||||
# initial goal IDs
|
||||
b_at.goal_id for b_at in before_audit_templates) or
|
||||
a_at.strategy_id not in (
|
||||
# initial strategy IDs
|
||||
b_at.strategy_id for b_at in before_audit_templates
|
||||
if b_at.strategy_id is not None)
|
||||
}
|
||||
|
||||
unmodified_audit_templates = {
|
||||
a_at.id for a_at in after_audit_templates
|
||||
if a_at.goal_id in (
|
||||
# initial goal IDs
|
||||
b_at.goal_id for b_at in before_audit_templates) and
|
||||
a_at.strategy_id in (
|
||||
# initial strategy IDs
|
||||
b_at.strategy_id for b_at in before_audit_templates
|
||||
if b_at.strategy_id is not None)
|
||||
}
|
||||
self.assertEqual(0, len(created_audits))
|
||||
self.assertEqual(0, len(created_action_plans))
|
||||
|
||||
self.assertEqual(2, strategy2.goal_id)
|
||||
self.assertIn(strategy2.name, created_strategies)
|
||||
self.assertNotEqual(strategy2.id,
|
||||
created_strategies[strategy2.name].id)
|
||||
|
||||
self.assertEqual(set([audit_template2.id,
|
||||
audit_template3.id,
|
||||
audit_template4.id]),
|
||||
modified_audit_templates)
|
||||
self.assertNotEqual(
|
||||
set([strategy2.id, strategy3.id, strategy4.id]),
|
||||
set(modified_strategies))
|
||||
self.assertEqual(set([strategy1.id]), set(unmodified_strategies))
|
||||
|
||||
self.assertEqual(
|
||||
set([audit_template2.id, audit_template3.id, audit_template4.id]),
|
||||
set(modified_audit_templates))
|
||||
self.assertEqual(set([audit_template1.id]),
|
||||
unmodified_audit_templates)
|
||||
set(unmodified_audit_templates))
|
||||
|
||||
self.assertEqual(
|
||||
set([audit2.id, audit3.id, audit4.id]),
|
||||
set(modified_audits))
|
||||
self.assertEqual(set([audit1.id]), set(unmodified_audits))
|
||||
|
||||
self.assertEqual(
|
||||
set([action_plan2.id, action_plan3.id, action_plan4.id]),
|
||||
set(modified_action_plans))
|
||||
self.assertTrue(
|
||||
all(ap.state == ap_objects.State.CANCELLED
|
||||
for ap in modified_action_plans.values()))
|
||||
self.assertEqual(set([action_plan1.id]), set(unmodified_action_plans))
|
||||
|
||||
def test_end2end_sync_goals_with_removed_goal_and_strategy(self):
|
||||
# ### Setup ### #
|
||||
@@ -417,11 +518,13 @@ class TestSyncer(base.DbTestCase):
|
||||
strategy1 = objects.Strategy(
|
||||
self.ctx, id=1, name="strategy_1", uuid=utils.generate_uuid(),
|
||||
display_name="Strategy 1", goal_id=goal1.id)
|
||||
# To be removed by the sync()
|
||||
# To be removed by the sync() because strategy entry point does not
|
||||
# exist anymore
|
||||
strategy2 = objects.Strategy(
|
||||
self.ctx, id=2, name="strategy_2", uuid=utils.generate_uuid(),
|
||||
display_name="Strategy 2", goal_id=goal1.id)
|
||||
# To be removed by the sync()
|
||||
# To be removed by the sync() because the goal has been soft deleted
|
||||
# and because the strategy entry point does not exist anymore
|
||||
strategy3 = objects.Strategy(
|
||||
self.ctx, id=3, name="strategy_3", uuid=utils.generate_uuid(),
|
||||
display_name="Original", goal_id=goal2.id)
|
||||
@@ -435,9 +538,9 @@ class TestSyncer(base.DbTestCase):
|
||||
# The strategy of this audit template will be dereferenced
|
||||
# as it does not exist anymore
|
||||
audit_template1 = objects.AuditTemplate(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
name="Synced AT1", goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Stale even after syncing because the goal has been soft deleted
|
||||
self.ctx, id=1, name="Synced AT1", uuid=utils.generate_uuid(),
|
||||
goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Stale after syncing because the goal has been soft deleted
|
||||
audit_template2 = objects.AuditTemplate(
|
||||
self.ctx, id=2, name="Synced AT2", uuid=utils.generate_uuid(),
|
||||
goal_id=goal2.id, strategy_id=strategy2.id)
|
||||
@@ -445,9 +548,39 @@ class TestSyncer(base.DbTestCase):
|
||||
audit_template1.create()
|
||||
audit_template2.create()
|
||||
|
||||
before_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
# Should stay unmodified after sync()
|
||||
audit1 = objects.Audit(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
goal_id=goal1.id, strategy_id=strategy1.id)
|
||||
# Stale after syncing because the goal has been soft deleted
|
||||
audit2 = objects.Audit(
|
||||
self.ctx, id=2, uuid=utils.generate_uuid(),
|
||||
goal_id=goal2.id, strategy_id=strategy2.id)
|
||||
audit1.create()
|
||||
audit2.create()
|
||||
|
||||
# Stale after syncing because its related strategy has been be
|
||||
# soft deleted
|
||||
action_plan1 = objects.ActionPlan(
|
||||
self.ctx, id=1, uuid=utils.generate_uuid(),
|
||||
audit_id=audit1.id, strategy_id=strategy1.id,
|
||||
first_action_id=None, state='DOESNOTMATTER',
|
||||
global_efficacy={})
|
||||
# Stale after syncing because its related goal has been soft deleted
|
||||
action_plan2 = objects.ActionPlan(
|
||||
self.ctx, id=2, uuid=utils.generate_uuid(),
|
||||
audit_id=audit2.id, strategy_id=strategy2.id,
|
||||
first_action_id=None, state='DOESNOTMATTER',
|
||||
global_efficacy={})
|
||||
|
||||
action_plan1.create()
|
||||
action_plan2.create()
|
||||
|
||||
before_goals = objects.Goal.list(self.ctx)
|
||||
before_strategies = objects.Strategy.list(self.ctx)
|
||||
before_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
before_audits = objects.Audit.list(self.ctx)
|
||||
before_action_plans = objects.ActionPlan.list(self.ctx)
|
||||
|
||||
# ### Action under test ### #
|
||||
|
||||
@@ -458,54 +591,66 @@ class TestSyncer(base.DbTestCase):
|
||||
|
||||
# ### Assertions ### #
|
||||
|
||||
after_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
after_goals = objects.Goal.list(self.ctx)
|
||||
after_strategies = objects.Strategy.list(self.ctx)
|
||||
after_audit_templates = objects.AuditTemplate.list(self.ctx)
|
||||
after_audits = objects.Audit.list(self.ctx)
|
||||
after_action_plans = objects.ActionPlan.list(self.ctx)
|
||||
|
||||
self.assertEqual(2, len(before_goals))
|
||||
self.assertEqual(3, len(before_strategies))
|
||||
self.assertEqual(2, len(before_audit_templates))
|
||||
self.assertEqual(2, len(before_audits))
|
||||
self.assertEqual(2, len(before_action_plans))
|
||||
self.assertEqual(1, len(after_goals))
|
||||
self.assertEqual(1, len(after_strategies))
|
||||
self.assertEqual(2, len(after_audit_templates))
|
||||
self.assertEqual(2, len(after_audits))
|
||||
self.assertEqual(2, len(after_action_plans))
|
||||
self.assertEqual(
|
||||
{"dummy_1"},
|
||||
set([g.name for g in after_goals]))
|
||||
self.assertEqual(
|
||||
{"strategy_1"},
|
||||
set([s.name for s in after_strategies]))
|
||||
created_goals = [ag for ag in after_goals
|
||||
if ag.uuid not in [bg.uuid for bg in before_goals]]
|
||||
created_strategies = [
|
||||
a_s for a_s in after_strategies
|
||||
if a_s.uuid not in [b_s.uuid for b_s in before_strategies]]
|
||||
|
||||
created_goals, modified_goals, unmodified_goals = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_goals, after_goals))
|
||||
|
||||
created_strategies, modified_strategies, unmodified_strategies = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_strategies, after_strategies))
|
||||
|
||||
(created_audit_templates, modified_audit_templates,
|
||||
unmodified_audit_templates) = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_audit_templates, after_audit_templates))
|
||||
|
||||
created_audits, modified_audits, unmodified_audits = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_audits, after_audits))
|
||||
|
||||
(created_action_plans, modified_action_plans,
|
||||
unmodified_action_plans) = (
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_action_plans, after_action_plans))
|
||||
|
||||
self.assertEqual(0, len(created_goals))
|
||||
self.assertEqual(0, len(created_strategies))
|
||||
|
||||
modified_audit_templates = {
|
||||
a_at.id for a_at in after_audit_templates
|
||||
if a_at.goal_id not in (
|
||||
# initial goal IDs
|
||||
b_at.goal_id for b_at in before_audit_templates) or
|
||||
a_at.strategy_id not in (
|
||||
# initial strategy IDs
|
||||
b_at.strategy_id for b_at in before_audit_templates
|
||||
if b_at.strategy_id is not None)
|
||||
}
|
||||
|
||||
unmodified_audit_templates = {
|
||||
a_at.id for a_at in after_audit_templates
|
||||
if a_at.goal_id in (
|
||||
# initial goal IDs
|
||||
b_at.goal_id for b_at in before_audit_templates) and
|
||||
a_at.strategy_id in (
|
||||
# initial strategy IDs
|
||||
b_at.strategy_id for b_at in before_audit_templates
|
||||
if b_at.strategy_id is not None)
|
||||
}
|
||||
self.assertEqual(0, len(created_audits))
|
||||
self.assertEqual(0, len(created_action_plans))
|
||||
|
||||
self.assertEqual(set([audit_template2.id]),
|
||||
modified_audit_templates)
|
||||
set(modified_audit_templates))
|
||||
self.assertEqual(set([audit_template1.id]),
|
||||
unmodified_audit_templates)
|
||||
set(unmodified_audit_templates))
|
||||
|
||||
self.assertEqual(set([audit2.id]), set(modified_audits))
|
||||
self.assertEqual(set([audit1.id]), set(unmodified_audits))
|
||||
|
||||
self.assertEqual(set([action_plan2.id]), set(modified_action_plans))
|
||||
self.assertTrue(
|
||||
all(ap.state == ap_objects.State.CANCELLED
|
||||
for ap in modified_action_plans.values()))
|
||||
self.assertEqual(set([action_plan1.id]), set(unmodified_action_plans))
|
||||
|
||||
Reference in New Issue
Block a user