During the strategy sync process, if goal_id can't be found in the goals table, will throw a KeyError exception. Change-Id: I62800ac5c69f4f5c7820908f2e777094a51a5541 Closes-Bug: #1711086
715 lines
30 KiB
Python
715 lines
30 KiB
Python
# -*- encoding: utf-8 -*-
|
|
# Copyright (c) 2016 b<>com
|
|
#
|
|
# 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.
|
|
|
|
import mock
|
|
|
|
from watcher.common import context
|
|
from watcher.common import utils
|
|
from watcher.decision_engine.loading import default
|
|
from watcher.decision_engine import sync
|
|
from watcher import objects
|
|
from watcher.tests.db import base
|
|
from watcher.tests.decision_engine import fake_goals
|
|
from watcher.tests.decision_engine import fake_strategies
|
|
|
|
|
|
class TestSyncer(base.DbTestCase):
|
|
|
|
def setUp(self):
|
|
super(TestSyncer, self).setUp()
|
|
self.ctx = context.make_context()
|
|
|
|
# This mock simulates the strategies discovery done in discover()
|
|
self.m_available_strategies = mock.Mock(return_value={
|
|
fake_strategies.FakeDummy1Strategy1.get_name():
|
|
fake_strategies.FakeDummy1Strategy1,
|
|
fake_strategies.FakeDummy1Strategy2.get_name():
|
|
fake_strategies.FakeDummy1Strategy2,
|
|
fake_strategies.FakeDummy2Strategy3.get_name():
|
|
fake_strategies.FakeDummy2Strategy3,
|
|
fake_strategies.FakeDummy2Strategy4.get_name():
|
|
fake_strategies.FakeDummy2Strategy4,
|
|
})
|
|
|
|
self.m_available_goals = mock.Mock(return_value={
|
|
fake_goals.FakeDummy1.get_name(): fake_goals.FakeDummy1,
|
|
fake_goals.FakeDummy2.get_name(): fake_goals.FakeDummy2,
|
|
})
|
|
|
|
self.goal1_spec = fake_goals.FakeDummy1(
|
|
config=mock.Mock()).get_efficacy_specification()
|
|
self.goal2_spec = fake_goals.FakeDummy2(
|
|
config=mock.Mock()).get_efficacy_specification()
|
|
|
|
p_goals_load = mock.patch.object(
|
|
default.DefaultGoalLoader, 'load',
|
|
side_effect=lambda goal: self.m_available_goals()[goal]())
|
|
p_goals = mock.patch.object(
|
|
default.DefaultGoalLoader, 'list_available',
|
|
self.m_available_goals)
|
|
p_strategies = mock.patch.object(
|
|
default.DefaultStrategyLoader, 'list_available',
|
|
self.m_available_strategies)
|
|
|
|
p_goals.start()
|
|
p_goals_load.start()
|
|
p_strategies.start()
|
|
|
|
self.syncer = sync.Syncer()
|
|
self.addCleanup(p_goals.stop)
|
|
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")
|
|
@mock.patch.object(objects.Strategy, "list")
|
|
@mock.patch.object(objects.Goal, "get_by_name")
|
|
@mock.patch.object(objects.Goal, "soft_delete")
|
|
@mock.patch.object(objects.Goal, "save")
|
|
@mock.patch.object(objects.Goal, "create")
|
|
@mock.patch.object(objects.Goal, "list")
|
|
def test_sync_empty_db(
|
|
self, m_g_list, m_g_create, m_g_save, m_g_soft_delete,
|
|
m_g_get_by_name, m_s_list, m_s_create, m_s_save, m_s_soft_delete):
|
|
m_g_get_by_name.side_effect = [
|
|
objects.Goal(self.ctx, id=i) for i in range(1, 10)]
|
|
m_g_list.return_value = []
|
|
m_s_list.return_value = []
|
|
|
|
self.syncer.sync()
|
|
|
|
self.assertEqual(2, m_g_create.call_count)
|
|
self.assertEqual(0, m_g_save.call_count)
|
|
self.assertEqual(0, m_g_soft_delete.call_count)
|
|
|
|
self.assertEqual(4, m_s_create.call_count)
|
|
self.assertEqual(0, m_s_save.call_count)
|
|
self.assertEqual(0, m_s_soft_delete.call_count)
|
|
|
|
@mock.patch.object(objects.Strategy, "soft_delete")
|
|
@mock.patch.object(objects.Strategy, "save")
|
|
@mock.patch.object(objects.Strategy, "create")
|
|
@mock.patch.object(objects.Strategy, "list")
|
|
@mock.patch.object(objects.Goal, "get_by_name")
|
|
@mock.patch.object(objects.Goal, "soft_delete")
|
|
@mock.patch.object(objects.Goal, "save")
|
|
@mock.patch.object(objects.Goal, "create")
|
|
@mock.patch.object(objects.Goal, "list")
|
|
def test_sync_with_existing_goal(
|
|
self, m_g_list, m_g_create, m_g_save, m_g_soft_delete,
|
|
m_g_get_by_name, m_s_list, m_s_create, m_s_save, m_s_soft_delete):
|
|
m_g_get_by_name.side_effect = [
|
|
objects.Goal(self.ctx, id=i) for i in range(1, 10)]
|
|
m_g_list.return_value = [
|
|
objects.Goal(self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_1", display_name="Dummy 1",
|
|
efficacy_specification=(
|
|
self.goal1_spec.serialize_indicators_specs()))
|
|
]
|
|
m_s_list.return_value = []
|
|
|
|
self.syncer.sync()
|
|
|
|
self.assertEqual(1, m_g_create.call_count)
|
|
self.assertEqual(0, m_g_save.call_count)
|
|
self.assertEqual(0, m_g_soft_delete.call_count)
|
|
|
|
self.assertEqual(4, m_s_create.call_count)
|
|
self.assertEqual(0, m_s_save.call_count)
|
|
self.assertEqual(0, m_s_soft_delete.call_count)
|
|
|
|
@mock.patch.object(objects.Strategy, "soft_delete")
|
|
@mock.patch.object(objects.Strategy, "save")
|
|
@mock.patch.object(objects.Strategy, "create")
|
|
@mock.patch.object(objects.Strategy, "list")
|
|
@mock.patch.object(objects.Goal, "get_by_name")
|
|
@mock.patch.object(objects.Goal, "soft_delete")
|
|
@mock.patch.object(objects.Goal, "save")
|
|
@mock.patch.object(objects.Goal, "create")
|
|
@mock.patch.object(objects.Goal, "list")
|
|
def test_sync_with_existing_strategy(
|
|
self, m_g_list, m_g_create, m_g_save, m_g_soft_delete,
|
|
m_g_get_by_name, m_s_list, m_s_create, m_s_save, m_s_soft_delete):
|
|
m_g_get_by_name.side_effect = [
|
|
objects.Goal(self.ctx, id=i) for i in range(1, 10)]
|
|
m_g_list.return_value = [
|
|
objects.Goal(self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_1", display_name="Dummy 1",
|
|
efficacy_specification=(
|
|
self.goal1_spec.serialize_indicators_specs()))
|
|
]
|
|
m_s_list.return_value = [
|
|
objects.Strategy(self.ctx, id=1, name="strategy_1",
|
|
goal_id=1, display_name="Strategy 1",
|
|
parameters_spec='{}')
|
|
]
|
|
self.syncer.sync()
|
|
|
|
self.assertEqual(1, m_g_create.call_count)
|
|
self.assertEqual(0, m_g_save.call_count)
|
|
self.assertEqual(0, m_g_soft_delete.call_count)
|
|
|
|
self.assertEqual(3, m_s_create.call_count)
|
|
self.assertEqual(0, m_s_save.call_count)
|
|
self.assertEqual(0, m_s_soft_delete.call_count)
|
|
|
|
@mock.patch.object(objects.Strategy, "soft_delete")
|
|
@mock.patch.object(objects.Strategy, "save")
|
|
@mock.patch.object(objects.Strategy, "create")
|
|
@mock.patch.object(objects.Strategy, "list")
|
|
@mock.patch.object(objects.Goal, "get_by_name")
|
|
@mock.patch.object(objects.Goal, "soft_delete")
|
|
@mock.patch.object(objects.Goal, "save")
|
|
@mock.patch.object(objects.Goal, "create")
|
|
@mock.patch.object(objects.Goal, "list")
|
|
def test_sync_with_modified_goal(
|
|
self, m_g_list, m_g_create, m_g_save, m_g_soft_delete,
|
|
m_g_get_by_name, m_s_list, m_s_create, m_s_save, m_s_soft_delete):
|
|
m_g_get_by_name.side_effect = [
|
|
objects.Goal(self.ctx, id=i) for i in range(1, 10)]
|
|
m_g_list.return_value = [objects.Goal(
|
|
self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_2", display_name="original",
|
|
efficacy_specification=self.goal2_spec.serialize_indicators_specs()
|
|
)]
|
|
m_s_list.return_value = []
|
|
self.syncer.sync()
|
|
|
|
self.assertEqual(2, m_g_create.call_count)
|
|
self.assertEqual(0, m_g_save.call_count)
|
|
self.assertEqual(1, m_g_soft_delete.call_count)
|
|
|
|
self.assertEqual(4, m_s_create.call_count)
|
|
self.assertEqual(0, m_s_save.call_count)
|
|
self.assertEqual(0, m_s_soft_delete.call_count)
|
|
|
|
@mock.patch.object(objects.Strategy, "soft_delete")
|
|
@mock.patch.object(objects.Strategy, "save")
|
|
@mock.patch.object(objects.Strategy, "create")
|
|
@mock.patch.object(objects.Strategy, "list")
|
|
@mock.patch.object(objects.Goal, "get_by_name")
|
|
@mock.patch.object(objects.Goal, "soft_delete")
|
|
@mock.patch.object(objects.Goal, "save")
|
|
@mock.patch.object(objects.Goal, "create")
|
|
@mock.patch.object(objects.Goal, "list")
|
|
def test_sync_with_modified_strategy(
|
|
self, m_g_list, m_g_create, m_g_save, m_g_soft_delete,
|
|
m_g_get_by_name, m_s_list, m_s_create, m_s_save, m_s_soft_delete):
|
|
m_g_get_by_name.side_effect = [
|
|
objects.Goal(self.ctx, id=i) for i in range(1, 10)]
|
|
m_g_list.return_value = [
|
|
objects.Goal(self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_1", display_name="Dummy 1",
|
|
efficacy_specification=(
|
|
self.goal1_spec.serialize_indicators_specs()))
|
|
]
|
|
m_s_list.return_value = [
|
|
objects.Strategy(self.ctx, id=1, name="strategy_1",
|
|
goal_id=1, display_name="original",
|
|
parameters_spec='{}')
|
|
]
|
|
self.syncer.sync()
|
|
|
|
self.assertEqual(1, m_g_create.call_count)
|
|
self.assertEqual(0, m_g_save.call_count)
|
|
self.assertEqual(0, m_g_soft_delete.call_count)
|
|
|
|
self.assertEqual(4, m_s_create.call_count)
|
|
self.assertEqual(0, m_s_save.call_count)
|
|
self.assertEqual(1, m_s_soft_delete.call_count)
|
|
|
|
def test_end2end_sync_goals_with_modified_goal_and_strategy(self):
|
|
# ### Setup ### #
|
|
|
|
# Here, we simulate goals and strategies already discovered in the past
|
|
# that were saved in DB
|
|
|
|
# Should stay unmodified after sync()
|
|
goal1 = objects.Goal(
|
|
self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_1", display_name="Dummy 1",
|
|
efficacy_specification=(
|
|
self.goal1_spec.serialize_indicators_specs()))
|
|
# Should be modified by the sync()
|
|
goal2 = objects.Goal(
|
|
self.ctx, id=2, uuid=utils.generate_uuid(),
|
|
name="dummy_2", display_name="Original",
|
|
efficacy_specification=self.goal2_spec.serialize_indicators_specs()
|
|
)
|
|
goal1.create()
|
|
goal2.create()
|
|
|
|
# Should stay unmodified after sync()
|
|
strategy1 = objects.Strategy(
|
|
self.ctx, id=1, name="strategy_1", uuid=utils.generate_uuid(),
|
|
display_name="Strategy 1", goal_id=goal1.id)
|
|
# 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 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=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)
|
|
strategy1.create()
|
|
strategy2.create()
|
|
strategy3.create()
|
|
strategy4.create()
|
|
|
|
# Here we simulate audit_templates that were already created in the
|
|
# past and hence saved within the Watcher DB
|
|
|
|
# Should stay unmodified after sync()
|
|
audit_template1 = objects.AuditTemplate(
|
|
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
|
|
# 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
|
|
# 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=goal1.id, strategy_id=strategy3.id)
|
|
# Modified because of both because its associated goal and associated
|
|
# strategy should be modified
|
|
audit_template4 = objects.AuditTemplate(
|
|
self.ctx, id=4, name="Synced AT4", uuid=utils.generate_uuid(),
|
|
goal_id=goal2.id, strategy_id=strategy4.id)
|
|
audit_template1.create()
|
|
audit_template2.create()
|
|
audit_template3.create()
|
|
audit_template4.create()
|
|
|
|
# Should stay unmodified after sync()
|
|
audit1 = objects.Audit(
|
|
self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
|
state=objects.audit.State.PENDING,
|
|
goal_id=goal1.id, strategy_id=strategy1.id, auto_trigger=False)
|
|
# 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(),
|
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
|
state=objects.audit.State.PENDING,
|
|
goal_id=goal2.id, strategy_id=strategy2.id, auto_trigger=False)
|
|
# 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(),
|
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
|
state=objects.audit.State.PENDING,
|
|
goal_id=goal1.id, strategy_id=strategy3.id, auto_trigger=False)
|
|
# 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(),
|
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
|
state=objects.audit.State.PENDING,
|
|
goal_id=goal2.id, strategy_id=strategy4.id, auto_trigger=False)
|
|
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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 ### #
|
|
|
|
try:
|
|
self.syncer.sync()
|
|
except Exception as exc:
|
|
self.fail(exc)
|
|
|
|
# ### Assertions ### #
|
|
|
|
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, 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',
|
|
'schema': 'Range(min=0, max=100, min_included=True, '
|
|
'max_included=True, msg=None)',
|
|
'unit': '%'}]
|
|
dummy_2_spec = []
|
|
self.assertEqual(
|
|
[dummy_1_spec, dummy_2_spec],
|
|
[g.efficacy_specification for g in after_goals])
|
|
|
|
self.assertEqual(1, len(created_goals))
|
|
self.assertEqual(3, len(created_strategies))
|
|
self.assertEqual(0, len(created_audits))
|
|
self.assertEqual(0, len(created_action_plans))
|
|
|
|
self.assertEqual(2, strategy2.goal_id)
|
|
|
|
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]),
|
|
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 == objects.action_plan.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 ### #
|
|
|
|
# We simulate the fact that we removed 2 strategies
|
|
self.m_available_strategies.return_value = {
|
|
fake_strategies.FakeDummy1Strategy1.get_name():
|
|
fake_strategies.FakeDummy1Strategy1
|
|
}
|
|
# We simulate the fact that we removed the dummy_2 goal
|
|
self.m_available_goals.return_value = {
|
|
fake_goals.FakeDummy1.get_name(): fake_goals.FakeDummy1,
|
|
}
|
|
# Should stay unmodified after sync()
|
|
goal1 = objects.Goal(
|
|
self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_1", display_name="Dummy 1",
|
|
efficacy_specification=self.goal1_spec.serialize_indicators_specs()
|
|
)
|
|
# To be removed by the sync()
|
|
goal2 = objects.Goal(
|
|
self.ctx, id=2, uuid=utils.generate_uuid(),
|
|
name="dummy_2", display_name="Dummy 2",
|
|
efficacy_specification=self.goal2_spec.serialize_indicators_specs()
|
|
)
|
|
goal1.create()
|
|
goal2.create()
|
|
|
|
# Should stay unmodified after sync()
|
|
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() 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() 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)
|
|
strategy1.create()
|
|
strategy2.create()
|
|
strategy3.create()
|
|
|
|
# Here we simulate audit_templates that were already created in the
|
|
# past and hence saved within the Watcher DB
|
|
|
|
# The strategy of this audit template will be dereferenced
|
|
# as it does not exist anymore
|
|
audit_template1 = objects.AuditTemplate(
|
|
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)
|
|
|
|
audit_template1.create()
|
|
audit_template2.create()
|
|
|
|
# Should stay unmodified after sync()
|
|
audit1 = objects.Audit(
|
|
self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
|
state=objects.audit.State.PENDING,
|
|
goal_id=goal1.id, strategy_id=strategy1.id, auto_trigger=False)
|
|
# Stale after syncing because the goal has been soft deleted
|
|
audit2 = objects.Audit(
|
|
self.ctx, id=2, uuid=utils.generate_uuid(),
|
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
|
state=objects.audit.State.PENDING,
|
|
goal_id=goal2.id, strategy_id=strategy2.id, auto_trigger=False)
|
|
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,
|
|
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,
|
|
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 ### #
|
|
|
|
try:
|
|
self.syncer.sync()
|
|
except Exception as exc:
|
|
self.fail(exc)
|
|
|
|
# ### Assertions ### #
|
|
|
|
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, 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))
|
|
self.assertEqual(0, len(created_audits))
|
|
self.assertEqual(0, len(created_action_plans))
|
|
|
|
self.assertEqual(set([audit_template2.id]),
|
|
set(modified_audit_templates))
|
|
self.assertEqual(set([audit_template1.id]),
|
|
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 == objects.action_plan.State.CANCELLED
|
|
for ap in modified_action_plans.values()))
|
|
self.assertEqual(set([action_plan1.id]), set(unmodified_action_plans))
|
|
|
|
def test_sync_strategies_with_removed_goal(self):
|
|
# ### Setup ### #
|
|
|
|
goal1 = objects.Goal(
|
|
self.ctx, id=1, uuid=utils.generate_uuid(),
|
|
name="dummy_1", display_name="Dummy 1",
|
|
efficacy_specification=self.goal1_spec.serialize_indicators_specs()
|
|
)
|
|
goal2 = objects.Goal(
|
|
self.ctx, id=2, uuid=utils.generate_uuid(),
|
|
name="dummy_2", display_name="Dummy 2",
|
|
efficacy_specification=self.goal2_spec.serialize_indicators_specs()
|
|
)
|
|
goal1.create()
|
|
goal2.create()
|
|
|
|
strategy1 = objects.Strategy(
|
|
self.ctx, id=1, name="strategy_1", uuid=utils.generate_uuid(),
|
|
display_name="Strategy 1", goal_id=goal1.id)
|
|
strategy2 = objects.Strategy(
|
|
self.ctx, id=2, name="strategy_2", uuid=utils.generate_uuid(),
|
|
display_name="Strategy 2", goal_id=goal2.id)
|
|
strategy1.create()
|
|
strategy2.create()
|
|
# to be removed by some reasons
|
|
goal2.soft_delete()
|
|
|
|
before_goals = objects.Goal.list(self.ctx)
|
|
before_strategies = objects.Strategy.list(self.ctx)
|
|
|
|
# ### Action under test ### #
|
|
|
|
try:
|
|
self.syncer.sync()
|
|
except Exception as exc:
|
|
self.fail(exc)
|
|
|
|
# ### Assertions ### #
|
|
|
|
after_goals = objects.Goal.list(self.ctx)
|
|
after_strategies = objects.Strategy.list(self.ctx)
|
|
|
|
self.assertEqual(1, len(before_goals))
|
|
self.assertEqual(2, len(before_strategies))
|
|
self.assertEqual(2, len(after_goals))
|
|
self.assertEqual(4, len(after_strategies))
|
|
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]))
|