From 9d2f8d11ec5bd633af6b9d5b4bb506c68f38bc4d Mon Sep 17 00:00:00 2001
From: licanwei
Date: Wed, 16 Aug 2017 02:32:02 -0700
Subject: [PATCH] Fix KeyError exception
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
---
watcher/decision_engine/sync.py | 8 ++++
watcher/tests/decision_engine/test_sync.py | 53 ++++++++++++++++++++++
2 files changed, 61 insertions(+)
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]))