Added Goal object + goal syncing

In this changeset, I added the Goal object into Watcher along with
a sync module that is responsible for syncing the goals with the
Watcher DB.

Partially Implements: blueprint get-goal-from-strategy

Change-Id: Ia3a2032dd9023d668c6f32ebbce44f8c1d77b0a3
This commit is contained in:
Vincent Françoise
2016-03-23 17:04:34 +01:00
parent be9058f3e3
commit 3b5ef15db6
7 changed files with 617 additions and 11 deletions

View File

@@ -51,11 +51,11 @@ class TestDbGoalFilters(base.DbTestCase):
def _soft_delete_goals(self):
with freezegun.freeze_time(self.FAKE_TODAY):
self.dbapi.soft_delete_goal(self.goal1.uuid)
self.dbapi.soft_delete_goal(self.goal1.id)
with freezegun.freeze_time(self.FAKE_OLD_DATE):
self.dbapi.soft_delete_goal(self.goal2.uuid)
self.dbapi.soft_delete_goal(self.goal2.id)
with freezegun.freeze_time(self.FAKE_OLDER_DATE):
self.dbapi.soft_delete_goal(self.goal3.uuid)
self.dbapi.soft_delete_goal(self.goal3.id)
def _update_goals(self):
with freezegun.freeze_time(self.FAKE_TODAY):
@@ -70,7 +70,7 @@ class TestDbGoalFilters(base.DbTestCase):
def test_get_goal_list_filter_deleted_true(self):
with freezegun.freeze_time(self.FAKE_TODAY):
self.dbapi.soft_delete_goal(self.goal1.uuid)
self.dbapi.soft_delete_goal(self.goal1.id)
res = self.dbapi.get_goal_list(
self.context, filters={'deleted': True})
@@ -79,7 +79,7 @@ class TestDbGoalFilters(base.DbTestCase):
def test_get_goal_list_filter_deleted_false(self):
with freezegun.freeze_time(self.FAKE_TODAY):
self.dbapi.soft_delete_goal(self.goal1.uuid)
self.dbapi.soft_delete_goal(self.goal1.id)
res = self.dbapi.get_goal_list(
self.context, filters={'deleted': False})

View File

@@ -0,0 +1,149 @@
# -*- 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.strategy.loading import default
from watcher.decision_engine.strategy.strategies import base as base_strategy
from watcher.decision_engine import sync
from watcher.objects import goal
from watcher.tests.db import base
class FakeStrategy(base_strategy.BaseStrategy):
DEFAULT_NAME = ""
DEFAULT_DESCRIPTION = ""
def execute(self, original_model):
pass
class FakeDummy1Strategy1(FakeStrategy):
DEFAULT_NAME = "DUMMY_1"
DEFAULT_DESCRIPTION = "Dummy 1"
ID = "STRATEGY_1"
class FakeDummy1Strategy2(FakeStrategy):
DEFAULT_NAME = "DUMMY_1"
DEFAULT_DESCRIPTION = "Dummy 1"
ID = "STRATEGY_2"
class FakeDummy2Strategy3(FakeStrategy):
DEFAULT_NAME = "DUMMY_2"
DEFAULT_DESCRIPTION = "Dummy 2"
ID = "STRATEGY_3"
class FakeDummy2Strategy4(FakeStrategy):
DEFAULT_NAME = "DUMMY_2"
DEFAULT_DESCRIPTION = "Other Dummy 2"
ID = "STRATEGY_4"
class TestSyncer(base.DbTestCase):
def setUp(self):
super(TestSyncer, self).setUp()
self.ctx = context.make_context()
self.m_available_strategies = mock.Mock(return_value={
FakeDummy1Strategy1.DEFAULT_NAME: FakeDummy1Strategy1,
FakeDummy1Strategy2.DEFAULT_NAME: FakeDummy1Strategy2,
FakeDummy2Strategy3.DEFAULT_NAME: FakeDummy2Strategy3,
FakeDummy2Strategy4.DEFAULT_NAME: FakeDummy2Strategy4,
})
p_strategies = mock.patch.object(
default.DefaultStrategyLoader, 'list_available',
self.m_available_strategies)
p_strategies.start()
self.syncer = sync.Syncer()
self.addCleanup(p_strategies.stop)
@mock.patch.object(goal.Goal, "soft_delete")
@mock.patch.object(goal.Goal, "save")
@mock.patch.object(goal.Goal, "create")
@mock.patch.object(goal.Goal, "list")
def test_sync_goals_empty_db(self, m_list, m_create,
m_save, m_soft_delete):
m_list.return_value = []
self.syncer.sync()
self.assertEqual(2, m_create.call_count)
self.assertEqual(0, m_save.call_count)
self.assertEqual(0, m_soft_delete.call_count)
@mock.patch.object(goal.Goal, "soft_delete")
@mock.patch.object(goal.Goal, "save")
@mock.patch.object(goal.Goal, "create")
@mock.patch.object(goal.Goal, "list")
def test_sync_goals_with_existing_goal(self, m_list, m_create,
m_save, m_soft_delete):
m_list.return_value = [
goal.Goal(self.ctx, id=1, uuid=utils.generate_uuid(),
name="DUMMY_1", display_name="Dummy 1")
]
self.syncer.sync()
self.assertEqual(1, m_create.call_count)
self.assertEqual(0, m_save.call_count)
self.assertEqual(0, m_soft_delete.call_count)
@mock.patch.object(goal.Goal, "soft_delete")
@mock.patch.object(goal.Goal, "save")
@mock.patch.object(goal.Goal, "create")
@mock.patch.object(goal.Goal, "list")
def test_sync_goals_with_modified_goal(self, m_list, m_create,
m_save, m_soft_delete):
m_list.return_value = [
goal.Goal(self.ctx, id=1, uuid=utils.generate_uuid(),
name="DUMMY_2", display_name="original")
]
self.syncer.sync()
self.assertEqual(2, m_create.call_count)
self.assertEqual(0, m_save.call_count)
self.assertEqual(1, m_soft_delete.call_count)
def test_end2end_sync_goals_with_modified_goal(self):
goal1 = goal.Goal(self.ctx, id=1, uuid=utils.generate_uuid(),
name="DUMMY_2", display_name="original")
goal1.create()
before_goals = goal.Goal.list(self.ctx)
try:
self.syncer.sync()
except Exception as exc:
self.fail(exc)
after_goals = goal.Goal.list(self.ctx)
self.assertEqual(1, len(before_goals))
self.assertEqual(2, len(after_goals))
self.assertEqual(
{"DUMMY_1", "DUMMY_2"},
set([g.name for g in after_goals]))
created_goals = [ag for ag in after_goals
if ag.uuid not in [bg.uuid for bg in before_goals]]
self.assertEqual(2, len(created_goals))
# TODO(v-francoise): check that the audit templates are re-synced with
# the new goal version

View File

@@ -0,0 +1,138 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# 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 import objects
from watcher.tests.db import base
from watcher.tests.db import utils
class TestGoalObject(base.DbTestCase):
def setUp(self):
super(TestGoalObject, self).setUp()
self.fake_goal = utils.get_test_goal()
def test_get_by_id(self):
goal_id = self.fake_goal['id']
with mock.patch.object(self.dbapi, 'get_goal_by_id',
autospec=True) as mock_get_goal:
mock_get_goal.return_value = self.fake_goal
goal = objects.Goal.get(self.context, goal_id)
mock_get_goal.assert_called_once_with(self.context, goal_id)
self.assertEqual(self.context, goal._context)
def test_get_by_uuid(self):
uuid = self.fake_goal['uuid']
with mock.patch.object(self.dbapi, 'get_goal_by_uuid',
autospec=True) as mock_get_goal:
mock_get_goal.return_value = self.fake_goal
goal = objects.Goal.get(self.context, uuid)
mock_get_goal.assert_called_once_with(self.context, uuid)
self.assertEqual(self.context, goal._context)
def test_get_by_name(self):
name = self.fake_goal['name']
with mock.patch.object(self.dbapi, 'get_goal_by_name',
autospec=True) as mock_get_goal:
mock_get_goal.return_value = self.fake_goal
goal = objects.Goal.get_by_name(
self.context,
name)
mock_get_goal.assert_called_once_with(self.context, name)
self.assertEqual(self.context, goal._context)
def test_list(self):
with mock.patch.object(self.dbapi, 'get_goal_list',
autospec=True) as mock_get_list:
mock_get_list.return_value = [self.fake_goal]
goals = objects.Goal.list(self.context)
self.assertEqual(1, mock_get_list.call_count)
self.assertEqual(1, len(goals))
self.assertIsInstance(goals[0], objects.Goal)
self.assertEqual(self.context, goals[0]._context)
def test_create(self):
with mock.patch.object(self.dbapi, 'create_goal',
autospec=True) as mock_create_goal:
mock_create_goal.return_value = self.fake_goal
goal = objects.Goal(self.context, **self.fake_goal)
goal.create()
mock_create_goal.assert_called_once_with(self.fake_goal)
self.assertEqual(self.context, goal._context)
def test_destroy(self):
goal_id = self.fake_goal['id']
with mock.patch.object(self.dbapi, 'get_goal_by_id',
autospec=True) as mock_get_goal:
mock_get_goal.return_value = self.fake_goal
with mock.patch.object(self.dbapi, 'destroy_goal',
autospec=True) \
as mock_destroy_goal:
goal = objects.Goal.get_by_id(self.context, goal_id)
goal.destroy()
mock_get_goal.assert_called_once_with(
self.context, goal_id)
mock_destroy_goal.assert_called_once_with(goal_id)
self.assertEqual(self.context, goal._context)
def test_save(self):
goal_id = self.fake_goal['id']
with mock.patch.object(self.dbapi, 'get_goal_by_id',
autospec=True) as mock_get_goal:
mock_get_goal.return_value = self.fake_goal
with mock.patch.object(self.dbapi, 'update_goal',
autospec=True) as mock_update_goal:
goal = objects.Goal.get_by_id(self.context, goal_id)
goal.display_name = 'DUMMY'
goal.save()
mock_get_goal.assert_called_once_with(self.context, goal_id)
mock_update_goal.assert_called_once_with(
goal_id, {'display_name': 'DUMMY'})
self.assertEqual(self.context, goal._context)
def test_refresh(self):
uuid = self.fake_goal['uuid']
fake_goal2 = utils.get_test_goal(name="BALANCE_LOAD")
returns = [self.fake_goal, fake_goal2]
expected = [mock.call(self.context, uuid),
mock.call(self.context, uuid)]
with mock.patch.object(self.dbapi, 'get_goal_by_uuid',
side_effect=returns,
autospec=True) as mock_get_goal:
goal = objects.Goal.get(self.context, uuid)
self.assertEqual("TEST", goal.name)
goal.refresh()
self.assertEqual("BALANCE_LOAD", goal.name)
self.assertEqual(expected, mock_get_goal.call_args_list)
self.assertEqual(self.context, goal._context)
def test_soft_delete(self):
uuid = self.fake_goal['uuid']
with mock.patch.object(self.dbapi, 'get_goal_by_uuid',
autospec=True) as mock_get_goal:
mock_get_goal.return_value = self.fake_goal
with mock.patch.object(self.dbapi, 'soft_delete_goal',
autospec=True) \
as mock_soft_delete_goal:
goal = objects.Goal.get_by_uuid(
self.context, uuid)
goal.soft_delete()
mock_get_goal.assert_called_once_with(
self.context, uuid)
mock_soft_delete_goal.assert_called_once_with(uuid)
self.assertEqual(self.context, goal._context)