diff --git a/watcher/decision_engine/sync.py b/watcher/decision_engine/sync.py index 17c331834..fd6025d80 100644 --- a/watcher/decision_engine/sync.py +++ b/watcher/decision_engine/sync.py @@ -78,6 +78,14 @@ class Syncer(object): """Strategies loaded from DB""" if self._available_strategies is None: self._available_strategies = objects.Strategy.list(self.ctx) + goal_ids = [g.id for g in self.available_goals] + stale_strategies = [s for s in self._available_strategies + if s.goal_id not in goal_ids] + for s in stale_strategies: + LOG.info("Can't find Goal id %d of strategy %s", + s.goal_id, s.name) + s.soft_delete() + self._available_strategies.remove(s) return self._available_strategies @property diff --git a/watcher/tests/decision_engine/test_sync.py b/watcher/tests/decision_engine/test_sync.py index 3a2f23e09..7c9a038e0 100644 --- a/watcher/tests/decision_engine/test_sync.py +++ b/watcher/tests/decision_engine/test_sync.py @@ -659,3 +659,56 @@ class TestSyncer(base.DbTestCase): 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]))