Complete unit tests for rule base.

This commit is contained in:
lvdongbing 2016-01-08 02:17:47 -05:00
parent 1056b8b6d7
commit 684bf3b72e
5 changed files with 206 additions and 135 deletions

View File

@ -92,57 +92,36 @@ class InvalidParameter(BileanException):
msg_fmt = _("Invalid value '%(value)s' specified for '%(name)s'") msg_fmt = _("Invalid value '%(value)s' specified for '%(name)s'")
class ClusterNotFound(BileanException):
msg_fmt = _("The cluster (%(cluster)s) could not be found.")
class NodeNotFound(BileanException):
msg_fmt = _("The node (%(node)s) could not be found.")
class RuleTypeNotFound(BileanException): class RuleTypeNotFound(BileanException):
msg_fmt = _("Rule type (%(rule_type)s) is not found.") msg_fmt = _("Rule type (%(rule_type)s) is not found.")
class ProfileTypeNotMatch(BileanException): class RuleTypeNotMatch(BileanException):
msg_fmt = _("%(message)s") msg_fmt = _("%(message)s")
class ProfileNotFound(BileanException): class RuleNotFound(BileanException):
msg_fmt = _("The profile (%(profile)s) could not be found.") msg_fmt = _("The rule (%(rule)s) could not be found.")
class ProfileNotSpecified(BileanException): class RuleNotSpecified(BileanException):
msg_fmt = _("Profile not specified.") msg_fmt = _("Rule not specified.")
class ProfileOperationFailed(BileanException): class RuleOperationFailed(BileanException):
msg_fmt = _("%(message)s") msg_fmt = _("%(message)s")
class ProfileOperationTimeout(BileanException): class RuleOperationTimeout(BileanException):
msg_fmt = _("%(message)s") msg_fmt = _("%(message)s")
class PolicyNotSpecified(BileanException):
msg_fmt = _("Policy not specified.")
class PolicyTypeNotFound(BileanException):
msg_fmt = _("Policy type (%(policy_type)s) is not found.")
class PolicyNotFound(BileanException): class PolicyNotFound(BileanException):
msg_fmt = _("The policy (%(policy)s) could not be found.") msg_fmt = _("The policy (%(policy)s) could not be found.")
class PolicyBindingNotFound(BileanException): class UserNotFound(BileanException):
msg_fmt = _("The policy (%(policy)s) is not found attached to the " msg_fmt = _("The user (%(user)s) could not be found.")
"specified cluster (%(identity)s).")
class PolicyTypeConflict(BileanException):
msg_fmt = _("The policy with type (%(policy_type)s) already exists.")
class InvalidSchemaError(BileanException): class InvalidSchemaError(BileanException):
@ -176,23 +155,6 @@ class RequestLimitExceeded(BileanException):
msg_fmt = _('Request limit exceeded: %(message)s') msg_fmt = _('Request limit exceeded: %(message)s')
class WebhookNotFound(BileanException):
msg_fmt = _("The webhook (%(webhook)s) could not be found.")
class ReceiverNotFound(BileanException):
msg_fmt = _("The receiver (%(receiver)s) could not be found.")
class ActionNotFound(BileanException):
msg_fmt = _("The action (%(action)s) could not be found.")
class ActionInProgress(BileanException):
msg_fmt = _("Cluster %(cluster_name)s already has an action (%(action)s) "
"in progress.")
class EventNotFound(BileanException): class EventNotFound(BileanException):
msg_fmt = _("The event (%(event)s) could not be found.") msg_fmt = _("The event (%(event)s) could not be found.")
@ -227,23 +189,12 @@ class TrustNotFound(InternalError):
msg_fmt = _("The trust for trustor (%(trustor)s) could not be found.") msg_fmt = _("The trust for trustor (%(trustor)s) could not be found.")
class ResourceCreationFailure(InternalError):
# Used when creating resources in other services
msg_fmt = _("Failed in creating %(rtype)s.")
class ResourceUpdateFailure(InternalError):
# Used when updating resources from other services
msg_fmt = _("Failed in updating %(resource)s.")
class ResourceDeletionFailure(InternalError): class ResourceDeletionFailure(InternalError):
# Used when deleting resources from other services # Used when deleting resources from other services
msg_fmt = _("Failed in deleting %(resource)s.") msg_fmt = _("Failed in deleting %(resource)s.")
class ResourceNotFound(InternalError): class ResourceNotFound(InternalError):
# Used when retrieving resources from other services
msg_fmt = _("The resource (%(resource)s) could not be found.") msg_fmt = _("The resource (%(resource)s) could not be found.")
@ -260,11 +211,6 @@ class InvalidSpec(InternalError):
msg_fmt = _("%(message)s") msg_fmt = _("%(message)s")
class PolicyNotAttached(InternalError):
msg_fmt = _("The policy (%(policy)s) is not attached to the specified "
"cluster (%(cluster)s).")
class HTTPExceptionDisguise(Exception): class HTTPExceptionDisguise(Exception):
"""Disguises HTTP exceptions. """Disguises HTTP exceptions.

View File

@ -24,7 +24,6 @@ from sqlalchemy.orm.session import Session
from bilean.common import consts from bilean.common import consts
from bilean.common import exception from bilean.common import exception
from bilean.common.i18n import _
from bilean.db.sqlalchemy import filters as db_filters from bilean.db.sqlalchemy import filters as db_filters
from bilean.db.sqlalchemy import migration from bilean.db.sqlalchemy import migration
from bilean.db.sqlalchemy import models from bilean.db.sqlalchemy import models
@ -133,14 +132,12 @@ def user_get(context, user_id, show_deleted=False, tenant_safe=True):
def user_update(context, user_id, values): def user_update(context, user_id, values):
user = user_get(context, user_id) user = user_get(context, user_id)
if not user: if user is None:
raise exception.NotFound(_('Attempt to update a user with id: ' raise exception.UserNotFound(user=user_id)
'%(id)s %(msg)s') % {
'id': user_id,
'msg': 'that does not exist'})
user.update(values) user.update(values)
user.save(_session(context)) user.save(_session(context))
return user
def user_create(context, values): def user_create(context, values):
@ -153,11 +150,9 @@ def user_create(context, values):
def user_delete(context, user_id): def user_delete(context, user_id):
session = _session(context) session = _session(context)
user = user_get(context, user_id) user = user_get(context, user_id)
if not user: if user is None:
raise exception.NotFound(_('Attempt to delete a user with id: ' return
'%(id)s %(msg)s') % {
'id': user_id,
'msg': 'that does not exist'})
# Delete all related resource records # Delete all related resource records
for resource in user.resources: for resource in user.resources:
session.delete(resource) session.delete(resource)
@ -196,7 +191,7 @@ def user_get_all(context, show_deleted=False, limit=None,
def rule_get(context, rule_id, show_deleted=False): def rule_get(context, rule_id, show_deleted=False):
query = model_query(context, models.Rule) query = model_query(context, models.Rule)
rule = query.get(rule_id) rule = query.filter_by(id=rule_id).first()
deleted_ok = show_deleted or context.show_deleted deleted_ok = show_deleted or context.show_deleted
if rule is None or rule.deleted_at is not None and not deleted_ok: if rule is None or rule.deleted_at is not None and not deleted_ok:
@ -239,11 +234,8 @@ def rule_create(context, values):
def rule_update(context, rule_id, values): def rule_update(context, rule_id, values):
rule = rule_get(context, rule_id) rule = rule_get(context, rule_id)
if not rule: if rule is None:
raise exception.NotFound(_('Attempt to update a rule with id: ' raise exception.RuleNotFound(rule=rule_id)
'%(id)s %(msg)s') % {
'id': rule_id,
'msg': 'that does not exist'})
rule.update(values) rule.update(values)
rule.save(_session(context)) rule.save(_session(context))
@ -252,11 +244,9 @@ def rule_update(context, rule_id, values):
def rule_delete(context, rule_id): def rule_delete(context, rule_id):
rule = rule_get(context, rule_id) rule = rule_get(context, rule_id)
if not rule: if rule is None:
raise exception.NotFound(_('Attempt to delete a rule with id: ' return
'%(id)s %(msg)s') % {
'id': rule_id,
'msg': 'that does not exist'})
session = Session.object_session(rule) session = Session.object_session(rule)
rule.soft_delete(session=session) rule.soft_delete(session=session)
session.flush() session.flush()
@ -315,11 +305,8 @@ def resource_create(context, values):
def resource_update(context, resource_id, values): def resource_update(context, resource_id, values):
resource = resource_get(context, resource_id) resource = resource_get(context, resource_id)
if not resource: if resource is None:
raise exception.NotFound(_('Attempt to update a resource with id: ' raise exception.ResourceNotFound(resource=resource_id)
'%(id)s %(msg)s') % {
'id': resource_id,
'msg': 'that does not exist'})
resource.update(values) resource.update(values)
resource.save(_session(context)) resource.save(_session(context))
@ -329,11 +316,9 @@ def resource_update(context, resource_id, values):
def resource_delete(context, resource_id, soft_delete=True): def resource_delete(context, resource_id, soft_delete=True):
resource = resource_get(context, resource_id) resource = resource_get(context, resource_id)
if not resource: if resource is None:
raise exception.NotFound(_('Attempt to delete a resource with id: ' return
'%(id)s %(msg)s') % {
'id': resource_id,
'msg': 'that does not exist'})
session = Session.object_session(resource) session = Session.object_session(resource)
if soft_delete: if soft_delete:
resource.soft_delete(session=session) resource.soft_delete(session=session)
@ -416,10 +401,8 @@ def job_delete(context, job_id):
job = model_query(context, models.Job).get(job_id) job = model_query(context, models.Job).get(job_id)
if job is None: if job is None:
raise exception.NotFound(_('Attempt to delete a job with id: ' return
'%(id)s %(msg)s') % {
'id': job_id,
'msg': 'that does not exist'})
session = Session.object_session(job) session = Session.object_session(job)
session.delete(job) session.delete(job)
session.flush() session.flush()
@ -469,11 +452,8 @@ def policy_create(context, values):
def policy_update(context, policy_id, values): def policy_update(context, policy_id, values):
policy = policy_get(context, policy_id) policy = policy_get(context, policy_id)
if not policy: if policy is None:
raise exception.NotFound(_('Attempt to update a policy with id: ' raise exception.PolicyNotFound(policy=policy_id)
'%(id)s %(msg)s') % {
'id': policy_id,
'msg': 'that does not exist'})
policy.update(values) policy.update(values)
policy.save(_session(context)) policy.save(_session(context))
@ -482,11 +462,9 @@ def policy_update(context, policy_id, values):
def policy_delete(context, policy_id): def policy_delete(context, policy_id):
policy = policy_get(context, policy_id) policy = policy_get(context, policy_id)
if not policy: if policy is None:
raise exception.NotFound(_('Attempt to delete a policy with id: ' return
'%(id)s %(msg)s') % {
'id': policy_id,
'msg': 'that does not exist'})
session = Session.object_session(policy) session = Session.object_session(policy)
policy.soft_delete(session=session) policy.soft_delete(session=session)
session.flush() session.flush()

View File

@ -14,12 +14,13 @@
SQLAlchemy models for Bilean data. SQLAlchemy models for Bilean data.
""" """
import uuid import six
from bilean.db.sqlalchemy import types from bilean.db.sqlalchemy import types
from oslo_db.sqlalchemy import models from oslo_db.sqlalchemy import models
from oslo_utils import timeutils from oslo_utils import timeutils
from oslo_utils import uuidutils
import sqlalchemy import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
@ -28,6 +29,7 @@ from sqlalchemy.orm import relationship
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
BASE = declarative_base() BASE = declarative_base()
UUID4 = uuidutils.generate_uuid
def get_session(): def get_session():
@ -70,7 +72,7 @@ class BileanBase(models.ModelBase):
if not session: if not session:
session = get_session() session = get_session()
session.begin() session.begin()
for k, v in values.iteritems(): for k, v in six.iteritems(values):
setattr(self, k, v) setattr(self, k, v)
session.commit() session.commit()
@ -121,7 +123,7 @@ class Policy(BASE, BileanBase, SoftDelete, models.TimestampMixin):
__tablename__ = 'policy' __tablename__ = 'policy'
id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True, id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())) default=lambda: UUID4())
name = sqlalchemy.Column(sqlalchemy.String(255)) name = sqlalchemy.Column(sqlalchemy.String(255))
rules = sqlalchemy.Column(types.List) rules = sqlalchemy.Column(types.List)
is_default = sqlalchemy.Column(sqlalchemy.Boolean, default=False) is_default = sqlalchemy.Column(sqlalchemy.Boolean, default=False)
@ -133,7 +135,7 @@ class Rule(BASE, BileanBase, SoftDelete, models.TimestampMixin):
__tablename__ = 'rule' __tablename__ = 'rule'
id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True, id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())) default=lambda: UUID4())
name = sqlalchemy.Column(sqlalchemy.String(255)) name = sqlalchemy.Column(sqlalchemy.String(255))
type = sqlalchemy.Column(sqlalchemy.String(255)) type = sqlalchemy.Column(sqlalchemy.String(255))
spec = sqlalchemy.Column(types.Dict) spec = sqlalchemy.Column(types.Dict)
@ -145,7 +147,7 @@ class Resource(BASE, BileanBase, SoftDelete, models.TimestampMixin):
__tablename__ = 'resource' __tablename__ = 'resource'
id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True, id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4())) default=lambda: UUID4())
user_id = sqlalchemy.Column( user_id = sqlalchemy.Column(
sqlalchemy.String(36), sqlalchemy.String(36),
sqlalchemy.ForeignKey('user.id'), sqlalchemy.ForeignKey('user.id'),
@ -166,8 +168,7 @@ class Event(BASE, BileanBase, SoftDelete):
__tablename__ = 'event' __tablename__ = 'event'
id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True, id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4()), default=lambda: UUID4(), unique=True)
unique=True)
user_id = sqlalchemy.Column(sqlalchemy.String(36), user_id = sqlalchemy.Column(sqlalchemy.String(36),
sqlalchemy.ForeignKey('user.id'), sqlalchemy.ForeignKey('user.id'),
nullable=False) nullable=False)

View File

@ -122,15 +122,16 @@ class Rule(object):
return cls.from_db_record(rule) return cls.from_db_record(rule)
@classmethod @classmethod
def load_all(cls, context, show_deleted=False, limit=None, def load_all(cls, context, limit=None, marker=None, sort_keys=None,
marker=None, sort_keys=None, sort_dir=None, sort_dir=None, filters=None, show_deleted=False):
filters=None):
'''Retrieve all rules from database.''' '''Retrieve all rules from database.'''
records = db_api.rule_get_all(context, show_deleted=show_deleted, records = db_api.rule_get_all(context, limit=limit,
limit=limit, marker=marker, marker=marker,
sort_keys=sort_keys, sort_dir=sort_dir, sort_keys=sort_keys,
filters=filters) sort_dir=sort_dir,
filters=filters,
show_deleted=show_deleted)
return [cls.from_db_record(record) for record in records] return [cls.from_db_record(record) for record in records]
@ -177,16 +178,6 @@ class Rule(object):
return NotImplemented return NotImplemented
def do_delete(self, obj):
'''For subclass to override.'''
return NotImplemented
def do_update(self, obj, new_rule, **params):
'''For subclass to override.'''
return NotImplemented
def to_dict(self): def to_dict(self):
rule_dict = { rule_dict = {
'id': self.id, 'id': self.id,

View File

@ -11,12 +11,11 @@
# under the License. # under the License.
import mock import mock
from oslo_utils import encodeutils
import six import six
from bilean.common import exception from bilean.common import exception
from bilean.common.i18n import _
from bilean.common import schema from bilean.common import schema
from bilean.common import utils as common_utils
from bilean.db import api as db_api from bilean.db import api as db_api
from bilean.engine import environment from bilean.engine import environment
from bilean.rules import base as rule_base from bilean.rules import base as rule_base
@ -106,3 +105,159 @@ class TestRuleBase(base.BileanTestCase):
self.assertRaises(exception.RuleTypeNotFound, self.assertRaises(exception.RuleTypeNotFound,
rule_base.Rule, rule_base.Rule,
'test-rule', bad_spec) 'test-rule', bad_spec)
def test_load(self):
rule = self._create_db_rule()
result = rule_base.Rule.load(self.context, rule.id)
self.assertEqual(rule.id, result.id)
self.assertEqual(rule.name, result.name)
self.assertEqual(rule.type, result.type)
self.assertEqual(rule.spec, result.spec)
self.assertEqual(rule.meta_data, result.metadata)
self.assertEqual({'key1': 'value1', 'key2': 2}, result.properties)
self.assertEqual(rule.created_at, result.created_at)
self.assertEqual(rule.updated_at, result.updated_at)
def test_load_not_found(self):
ex = self.assertRaises(exception.RuleNotFound,
rule_base.Rule.load,
self.context, 'fake-rule', None)
self.assertEqual('The rule (fake-rule) could not be found.',
six.text_type(ex))
ex = self.assertRaises(exception.RuleNotFound,
rule_base.Rule.load,
self.context, None, None)
self.assertEqual('The rule (None) could not be found.',
six.text_type(ex))
def test_load_all(self):
result = rule_base.Rule.load_all(self.context)
self.assertEqual([], list(result))
rule1 = self._create_db_rule(name='rule-1', id='ID1')
rule2 = self._create_db_rule(name='rule-2', id='ID2')
result = rule_base.Rule.load_all(self.context)
rules = list(result)
self.assertEqual(2, len(rules))
self.assertEqual(rule1.id, rules[0].id)
self.assertEqual(rule2.id, rules[1].id)
@mock.patch.object(db_api, 'rule_get_all')
def test_load_all_with_params(self, mock_get_all):
mock_get_all.return_value = []
res = list(rule_base.Rule.load_all(self.context))
self.assertEqual([], res)
mock_get_all.assert_called_once_with(self.context, limit=None,
marker=None, sort_keys=None,
sort_dir=None, filters=None,
show_deleted=False)
mock_get_all.reset_mock()
res = list(rule_base.Rule.load_all(self.context, limit=1,
marker='MARKER',
sort_keys=['K1'],
sort_dir='asc',
filters={'name': 'fake-name'}))
self.assertEqual([], res)
mock_get_all.assert_called_once_with(self.context, limit=1,
marker='MARKER',
sort_keys=['K1'],
sort_dir='asc',
filters={'name': 'fake-name'},
show_deleted=False)
def test_delete(self):
rule = self._create_db_rule()
rule_id = rule.id
res = rule_base.Rule.delete(self.context, rule_id)
self.assertIsNone(res)
self.assertRaises(exception.RuleNotFound,
rule_base.Rule.load,
self.context, rule_id, None)
def test_delete_not_found(self):
result = rule_base.Rule.delete(self.context, 'fake-rule')
self.assertIsNone(result)
def test_store_for_create(self):
rule = self._create_rule('test-rule')
self.assertIsNone(rule.id)
rule_id = rule.store(self.context)
self.assertIsNotNone(rule_id)
self.assertEqual(rule_id, rule.id)
result = db_api.rule_get(self.context, rule_id)
self.assertIsNotNone(result)
self.assertEqual('test-rule', result.name)
self.assertEqual(rule_id, result.id)
self.assertEqual(rule.type, result.type)
self.assertEqual(rule.spec, result.spec)
self.assertEqual(rule.metadata, result.meta_data)
self.assertIsNotNone(result.created_at)
self.assertIsNone(result.updated_at)
def test_store_for_update(self):
rule = self._create_rule('test-rule')
self.assertIsNone(rule.id)
rule_id = rule.store(self.context)
self.assertIsNotNone(rule_id)
self.assertEqual(rule_id, rule.id)
rule.name = 'test-rule-1'
rule.metadata = {'key': 'value'}
new_id = rule.store(self.context)
self.assertEqual(rule_id, new_id)
result = db_api.rule_get(self.context, rule_id)
self.assertIsNotNone(result)
self.assertEqual('test-rule-1', result.name)
self.assertEqual({'key': 'value'}, result.meta_data)
self.assertIsNotNone(rule.created_at)
self.assertIsNotNone(rule.updated_at)
def test_to_dict(self):
rule = self._create_rule('test-rule')
rule_id = rule.store(self.context)
self.assertIsNotNone(rule_id)
expected = {
'id': rule_id,
'name': rule.name,
'type': rule.type,
'spec': rule.spec,
'metadata': rule.metadata,
'created_at': common_utils.format_time(rule.created_at),
'updated_at': None,
'deleted_at': None,
}
result = rule_base.Rule.load(self.context, rule_id=rule.id)
self.assertEqual(expected, result.to_dict())
def test_get_schema(self):
expected = {
'key1': {
'default': 'value1',
'description': 'First key',
'readonly': False,
'required': False,
'type': 'String'
},
'key2': {
'description': 'Second key',
'readonly': False,
'required': True,
'type': 'Integer'
},
}
res = DummyRule.get_schema()
self.assertEqual(expected, res)