aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/tests/unit/common
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/tests/unit/common')
-rw-r--r--keystone-moon/keystone/tests/unit/common/test_connection_pool.py16
-rw-r--r--keystone-moon/keystone/tests/unit/common/test_injection.py57
-rw-r--r--keystone-moon/keystone/tests/unit/common/test_ldap.py88
-rw-r--r--keystone-moon/keystone/tests/unit/common/test_notifications.py180
-rw-r--r--keystone-moon/keystone/tests/unit/common/test_utils.py2
5 files changed, 224 insertions, 119 deletions
diff --git a/keystone-moon/keystone/tests/unit/common/test_connection_pool.py b/keystone-moon/keystone/tests/unit/common/test_connection_pool.py
index 74d0420c..3813e033 100644
--- a/keystone-moon/keystone/tests/unit/common/test_connection_pool.py
+++ b/keystone-moon/keystone/tests/unit/common/test_connection_pool.py
@@ -10,9 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import threading
import time
import mock
+import six
from six.moves import queue
import testtools
from testtools import matchers
@@ -117,3 +119,17 @@ class TestConnectionPool(core.TestCase):
# after it is available.
connection_pool.put_nowait(conn)
_acquire_connection()
+
+
+class TestMemcacheClientOverrides(core.BaseTestCase):
+
+ def test_client_stripped_of_threading_local(self):
+ """threading.local overrides are restored for _MemcacheClient"""
+ client_class = _memcache_pool._MemcacheClient
+ # get the genuine thread._local from MRO
+ thread_local = client_class.__mro__[2]
+ self.assertTrue(thread_local is threading.local)
+ for field in six.iterkeys(thread_local.__dict__):
+ if field not in ('__dict__', '__weakref__'):
+ self.assertNotEqual(id(getattr(thread_local, field, None)),
+ id(getattr(client_class, field, None)))
diff --git a/keystone-moon/keystone/tests/unit/common/test_injection.py b/keystone-moon/keystone/tests/unit/common/test_injection.py
index 86bb3c24..b4c23a84 100644
--- a/keystone-moon/keystone/tests/unit/common/test_injection.py
+++ b/keystone-moon/keystone/tests/unit/common/test_injection.py
@@ -21,6 +21,7 @@ from keystone.tests import unit as tests
class TestDependencyInjection(tests.BaseTestCase):
def setUp(self):
super(TestDependencyInjection, self).setUp()
+ dependency.reset()
self.addCleanup(dependency.reset)
def test_dependency_injection(self):
@@ -210,62 +211,6 @@ class TestDependencyInjection(tests.BaseTestCase):
self.assertFalse(dependency._REGISTRY)
- def test_optional_dependency_not_provided(self):
- requirement_name = uuid.uuid4().hex
-
- @dependency.optional(requirement_name)
- class C1(object):
- pass
-
- c1_inst = C1()
-
- dependency.resolve_future_dependencies()
-
- self.assertIsNone(getattr(c1_inst, requirement_name))
-
- def test_optional_dependency_provided(self):
- requirement_name = uuid.uuid4().hex
-
- @dependency.optional(requirement_name)
- class C1(object):
- pass
-
- @dependency.provider(requirement_name)
- class P1(object):
- pass
-
- c1_inst = C1()
- p1_inst = P1()
-
- dependency.resolve_future_dependencies()
-
- self.assertIs(getattr(c1_inst, requirement_name), p1_inst)
-
- def test_optional_and_required(self):
- p1_name = uuid.uuid4().hex
- p2_name = uuid.uuid4().hex
- optional_name = uuid.uuid4().hex
-
- @dependency.provider(p1_name)
- @dependency.requires(p2_name)
- @dependency.optional(optional_name)
- class P1(object):
- pass
-
- @dependency.provider(p2_name)
- @dependency.requires(p1_name)
- class P2(object):
- pass
-
- p1 = P1()
- p2 = P2()
-
- dependency.resolve_future_dependencies()
-
- self.assertIs(getattr(p1, p2_name), p2)
- self.assertIs(getattr(p2, p1_name), p1)
- self.assertIsNone(getattr(p1, optional_name))
-
def test_get_provider(self):
# Can get the instance of a provider using get_provider
diff --git a/keystone-moon/keystone/tests/unit/common/test_ldap.py b/keystone-moon/keystone/tests/unit/common/test_ldap.py
index 41568890..d3ce8cd2 100644
--- a/keystone-moon/keystone/tests/unit/common/test_ldap.py
+++ b/keystone-moon/keystone/tests/unit/common/test_ldap.py
@@ -11,23 +11,24 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
+import tempfile
import uuid
+import fixtures
import ldap.dn
import mock
from oslo_config import cfg
from testtools import matchers
-import os
-import shutil
-import tempfile
-
+from keystone.common import driver_hints
from keystone.common import ldap as ks_ldap
from keystone.common.ldap import core as common_ldap_core
from keystone.tests import unit as tests
from keystone.tests.unit import default_fixtures
from keystone.tests.unit import fakeldap
+
CONF = cfg.CONF
@@ -218,9 +219,7 @@ class LDAPDeleteTreeTest(tests.TestCase):
def config_overrides(self):
super(LDAPDeleteTreeTest, self).config_overrides()
- self.config_fixture.config(
- group='identity',
- driver='keystone.identity.backends.ldap.Identity')
+ self.config_fixture.config(group='identity', driver='ldap')
def config_files(self):
config_files = super(LDAPDeleteTreeTest, self).config_files()
@@ -311,8 +310,7 @@ class SslTlsTest(tests.TestCase):
def test_certdir_trust_tls(self):
# We need this to actually exist, so we create a tempdir.
- certdir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, certdir)
+ certdir = self.useFixture(fixtures.TempDir()).path
self.config_fixture.config(group='ldap',
url='ldap://localhost',
use_tls=True,
@@ -340,8 +338,7 @@ class SslTlsTest(tests.TestCase):
def test_certdir_trust_ldaps(self):
# We need this to actually exist, so we create a tempdir.
- certdir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, certdir)
+ certdir = self.useFixture(fixtures.TempDir()).path
self.config_fixture.config(group='ldap',
url='ldaps://localhost',
use_tls=False,
@@ -372,9 +369,7 @@ class LDAPPagedResultsTest(tests.TestCase):
def config_overrides(self):
super(LDAPPagedResultsTest, self).config_overrides()
- self.config_fixture.config(
- group='identity',
- driver='keystone.identity.backends.ldap.Identity')
+ self.config_fixture.config(group='identity', driver='ldap')
def config_files(self):
config_files = super(LDAPPagedResultsTest, self).config_files()
@@ -500,3 +495,68 @@ class CommonLdapTestCase(tests.BaseTestCase):
py_result = ks_ldap.convert_ldap_result(result)
# The user name should still be a string value.
self.assertEqual(user_name, py_result[0][1]['user_name'][0])
+
+
+class LDAPFilterQueryCompositionTest(tests.TestCase):
+ """These test cases test LDAP filter generation."""
+
+ def setUp(self):
+ super(LDAPFilterQueryCompositionTest, self).setUp()
+
+ self.base_ldap = ks_ldap.BaseLdap(self.config_fixture.conf)
+
+ # The tests need an attribute mapping to use.
+ self.attribute_name = uuid.uuid4().hex
+ self.filter_attribute_name = uuid.uuid4().hex
+ self.base_ldap.attribute_mapping = {
+ self.attribute_name: self.filter_attribute_name
+ }
+
+ def test_return_query_with_no_hints(self):
+ hints = driver_hints.Hints()
+ # NOTE: doesn't have to be a real query, we just need to make sure the
+ # same string is returned if there are no hints.
+ query = uuid.uuid4().hex
+ self.assertEqual(query,
+ self.base_ldap.filter_query(hints=hints, query=query))
+
+ # make sure the default query is an empty string
+ self.assertEqual('', self.base_ldap.filter_query(hints=hints))
+
+ def test_filter_with_empty_query_and_hints_set(self):
+ hints = driver_hints.Hints()
+ username = uuid.uuid4().hex
+ hints.add_filter(name=self.attribute_name,
+ value=username,
+ comparator='equals',
+ case_sensitive=False)
+ expected_ldap_filter = '(&(%s=%s))' % (
+ self.filter_attribute_name, username)
+ self.assertEqual(expected_ldap_filter,
+ self.base_ldap.filter_query(hints=hints))
+
+ def test_filter_with_both_query_and_hints_set(self):
+ hints = driver_hints.Hints()
+ # NOTE: doesn't have to be a real query, we just need to make sure the
+ # filter string is concatenated correctly
+ query = uuid.uuid4().hex
+ username = uuid.uuid4().hex
+ expected_result = '(&%(query)s(%(user_name_attr)s=%(username)s))' % (
+ {'query': query,
+ 'user_name_attr': self.filter_attribute_name,
+ 'username': username})
+ hints.add_filter(self.attribute_name, username)
+ self.assertEqual(expected_result,
+ self.base_ldap.filter_query(hints=hints, query=query))
+
+ def test_filter_with_hints_and_query_is_none(self):
+ hints = driver_hints.Hints()
+ username = uuid.uuid4().hex
+ hints.add_filter(name=self.attribute_name,
+ value=username,
+ comparator='equals',
+ case_sensitive=False)
+ expected_ldap_filter = '(&(%s=%s))' % (
+ self.filter_attribute_name, username)
+ self.assertEqual(expected_ldap_filter,
+ self.base_ldap.filter_query(hints=hints, query=None))
diff --git a/keystone-moon/keystone/tests/unit/common/test_notifications.py b/keystone-moon/keystone/tests/unit/common/test_notifications.py
index 55dd556d..2d872733 100644
--- a/keystone-moon/keystone/tests/unit/common/test_notifications.py
+++ b/keystone-moon/keystone/tests/unit/common/test_notifications.py
@@ -23,10 +23,9 @@ from pycadf import cadftaxonomy
from pycadf import cadftype
from pycadf import eventfactory
from pycadf import resource as cadfresource
-import testtools
-from keystone.common import dependency
from keystone import notifications
+from keystone.tests import unit
from keystone.tests.unit import test_v3
@@ -53,7 +52,7 @@ def register_callback(operation, resource_type=EXP_RESOURCE_TYPE):
return callback
-class AuditNotificationsTestCase(testtools.TestCase):
+class AuditNotificationsTestCase(unit.BaseTestCase):
def setUp(self):
super(AuditNotificationsTestCase, self).setUp()
self.config_fixture = self.useFixture(config_fixture.Config(CONF))
@@ -96,7 +95,7 @@ class AuditNotificationsTestCase(testtools.TestCase):
DISABLED_OPERATION)
-class NotificationsWrapperTestCase(testtools.TestCase):
+class NotificationsWrapperTestCase(unit.BaseTestCase):
def create_fake_ref(self):
resource_id = uuid.uuid4().hex
return resource_id, {
@@ -174,14 +173,7 @@ class NotificationsWrapperTestCase(testtools.TestCase):
self.assertFalse(callback.called)
-class NotificationsTestCase(testtools.TestCase):
- def setUp(self):
- super(NotificationsTestCase, self).setUp()
-
- # these should use self.config_fixture.config(), but they haven't
- # been registered yet
- CONF.rpc_backend = 'fake'
- CONF.notification_driver = ['fake']
+class NotificationsTestCase(unit.BaseTestCase):
def test_send_notification(self):
"""Test the private method _send_notification to ensure event_type,
@@ -324,7 +316,7 @@ class NotificationsForEntities(BaseNotificationTest):
def test_create_project(self):
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
self._assert_last_note(
project_ref['id'], CREATED_OPERATION, 'project')
self._assert_last_audit(project_ref['id'], CREATED_OPERATION,
@@ -371,8 +363,8 @@ class NotificationsForEntities(BaseNotificationTest):
def test_delete_project(self):
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
- self.assignment_api.delete_project(project_ref['id'])
+ self.resource_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.delete_project(project_ref['id'])
self._assert_last_note(
project_ref['id'], DELETED_OPERATION, 'project')
self._assert_last_audit(project_ref['id'], DELETED_OPERATION,
@@ -403,19 +395,19 @@ class NotificationsForEntities(BaseNotificationTest):
def test_update_domain(self):
domain_ref = self.new_domain_ref()
- self.assignment_api.create_domain(domain_ref['id'], domain_ref)
+ self.resource_api.create_domain(domain_ref['id'], domain_ref)
domain_ref['description'] = uuid.uuid4().hex
- self.assignment_api.update_domain(domain_ref['id'], domain_ref)
+ self.resource_api.update_domain(domain_ref['id'], domain_ref)
self._assert_last_note(domain_ref['id'], UPDATED_OPERATION, 'domain')
self._assert_last_audit(domain_ref['id'], UPDATED_OPERATION, 'domain',
cadftaxonomy.SECURITY_DOMAIN)
def test_delete_domain(self):
domain_ref = self.new_domain_ref()
- self.assignment_api.create_domain(domain_ref['id'], domain_ref)
+ self.resource_api.create_domain(domain_ref['id'], domain_ref)
domain_ref['enabled'] = False
- self.assignment_api.update_domain(domain_ref['id'], domain_ref)
- self.assignment_api.delete_domain(domain_ref['id'])
+ self.resource_api.update_domain(domain_ref['id'], domain_ref)
+ self.resource_api.delete_domain(domain_ref['id'])
self._assert_last_note(domain_ref['id'], DELETED_OPERATION, 'domain')
self._assert_last_audit(domain_ref['id'], DELETED_OPERATION, 'domain',
cadftaxonomy.SECURITY_DOMAIN)
@@ -542,19 +534,19 @@ class NotificationsForEntities(BaseNotificationTest):
def test_disable_domain(self):
domain_ref = self.new_domain_ref()
- self.assignment_api.create_domain(domain_ref['id'], domain_ref)
+ self.resource_api.create_domain(domain_ref['id'], domain_ref)
domain_ref['enabled'] = False
- self.assignment_api.update_domain(domain_ref['id'], domain_ref)
+ self.resource_api.update_domain(domain_ref['id'], domain_ref)
self._assert_notify_sent(domain_ref['id'], 'disabled', 'domain',
public=False)
def test_disable_of_disabled_domain_does_not_notify(self):
domain_ref = self.new_domain_ref()
domain_ref['enabled'] = False
- self.assignment_api.create_domain(domain_ref['id'], domain_ref)
+ self.resource_api.create_domain(domain_ref['id'], domain_ref)
# The domain_ref above is not changed during the create process. We
# can use the same ref to perform the update.
- self.assignment_api.update_domain(domain_ref['id'], domain_ref)
+ self.resource_api.update_domain(domain_ref['id'], domain_ref)
self._assert_notify_not_sent(domain_ref['id'], 'disabled', 'domain',
public=False)
@@ -568,8 +560,8 @@ class NotificationsForEntities(BaseNotificationTest):
def test_update_project(self):
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
- self.assignment_api.update_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.update_project(project_ref['id'], project_ref)
self._assert_notify_sent(
project_ref['id'], UPDATED_OPERATION, 'project', public=True)
self._assert_last_audit(project_ref['id'], UPDATED_OPERATION,
@@ -577,27 +569,27 @@ class NotificationsForEntities(BaseNotificationTest):
def test_disable_project(self):
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
project_ref['enabled'] = False
- self.assignment_api.update_project(project_ref['id'], project_ref)
+ self.resource_api.update_project(project_ref['id'], project_ref)
self._assert_notify_sent(project_ref['id'], 'disabled', 'project',
public=False)
def test_disable_of_disabled_project_does_not_notify(self):
project_ref = self.new_project_ref(domain_id=self.domain_id)
project_ref['enabled'] = False
- self.assignment_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
# The project_ref above is not changed during the create process. We
# can use the same ref to perform the update.
- self.assignment_api.update_project(project_ref['id'], project_ref)
+ self.resource_api.update_project(project_ref['id'], project_ref)
self._assert_notify_not_sent(project_ref['id'], 'disabled', 'project',
public=False)
def test_update_project_does_not_send_disable(self):
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
project_ref['enabled'] = True
- self.assignment_api.update_project(project_ref['id'], project_ref)
+ self.resource_api.update_project(project_ref['id'], project_ref)
self._assert_last_note(
project_ref['id'], UPDATED_OPERATION, 'project')
self._assert_notify_not_sent(project_ref['id'], 'disabled', 'project')
@@ -665,7 +657,7 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
def test_notification_received(self):
callback = register_callback(CREATED_OPERATION, 'project')
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
self.assertTrue(callback.called)
def test_notification_method_not_callable(self):
@@ -694,14 +686,14 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
resource_type,
self._project_deleted_callback)
- def test_provider_event_callbacks_subscription(self):
+ def test_provider_event_callback_subscription(self):
callback_called = []
- @dependency.provider('foo_api')
+ @notifications.listener
class Foo(object):
def __init__(self):
self.event_callbacks = {
- CREATED_OPERATION: {'project': [self.foo_callback]}}
+ CREATED_OPERATION: {'project': self.foo_callback}}
def foo_callback(self, service, resource_type, operation,
payload):
@@ -710,24 +702,73 @@ class TestEventCallbacks(test_v3.RestfulTestCase):
Foo()
project_ref = self.new_project_ref(domain_id=self.domain_id)
- self.assignment_api.create_project(project_ref['id'], project_ref)
+ self.resource_api.create_project(project_ref['id'], project_ref)
self.assertEqual([True], callback_called)
+ def test_provider_event_callbacks_subscription(self):
+ callback_called = []
+
+ @notifications.listener
+ class Foo(object):
+ def __init__(self):
+ self.event_callbacks = {
+ CREATED_OPERATION: {
+ 'project': [self.callback_0, self.callback_1]}}
+
+ def callback_0(self, service, resource_type, operation, payload):
+ # uses callback_called from the closure
+ callback_called.append('cb0')
+
+ def callback_1(self, service, resource_type, operation, payload):
+ # uses callback_called from the closure
+ callback_called.append('cb1')
+
+ Foo()
+ project_ref = self.new_project_ref(domain_id=self.domain_id)
+ self.resource_api.create_project(project_ref['id'], project_ref)
+ self.assertItemsEqual(['cb1', 'cb0'], callback_called)
+
def test_invalid_event_callbacks(self):
- @dependency.provider('foo_api')
+ @notifications.listener
class Foo(object):
def __init__(self):
self.event_callbacks = 'bogus'
- self.assertRaises(ValueError, Foo)
+ self.assertRaises(AttributeError, Foo)
def test_invalid_event_callbacks_event(self):
- @dependency.provider('foo_api')
+ @notifications.listener
class Foo(object):
def __init__(self):
self.event_callbacks = {CREATED_OPERATION: 'bogus'}
- self.assertRaises(ValueError, Foo)
+ self.assertRaises(AttributeError, Foo)
+
+ def test_using_an_unbound_method_as_a_callback_fails(self):
+ # NOTE(dstanek): An unbound method is when you reference a method
+ # from a class object. You'll get a method that isn't bound to a
+ # particular instance so there is no magic 'self'. You can call it,
+ # but you have to pass in the instance manually like: C.m(C()).
+ # If you reference the method from an instance then you get a method
+ # that effectively curries the self argument for you
+ # (think functools.partial). Obviously is we don't have an
+ # instance then we can't call the method.
+ @notifications.listener
+ class Foo(object):
+ def __init__(self):
+ self.event_callbacks = {CREATED_OPERATION:
+ {'project': Foo.callback}}
+
+ def callback(self, *args):
+ pass
+
+ # TODO(dstanek): it would probably be nice to fail early using
+ # something like:
+ # self.assertRaises(TypeError, Foo)
+ Foo()
+ project_ref = self.new_project_ref(domain_id=self.domain_id)
+ self.assertRaises(TypeError, self.resource_api.create_project,
+ project_ref['id'], project_ref)
class CadfNotificationsWrapperTestCase(test_v3.RestfulTestCase):
@@ -759,13 +800,14 @@ class CadfNotificationsWrapperTestCase(test_v3.RestfulTestCase):
'action': action,
'initiator': initiator,
'event': event,
+ 'event_type': event_type,
'send_notification_called': True}
self._notifications.append(note)
self.useFixture(mockpatch.PatchObject(
notifications, '_send_audit_notification', fake_notify))
- def _assert_last_note(self, action, user_id):
+ def _assert_last_note(self, action, user_id, event_type=None):
self.assertTrue(self._notifications)
note = self._notifications[-1]
self.assertEqual(note['action'], action)
@@ -773,6 +815,8 @@ class CadfNotificationsWrapperTestCase(test_v3.RestfulTestCase):
self.assertEqual(initiator.id, user_id)
self.assertEqual(initiator.host.address, self.LOCAL_HOST)
self.assertTrue(note['send_notification_called'])
+ if event_type:
+ self.assertEqual(note['event_type'], event_type)
def _assert_event(self, role_id, project=None, domain=None,
user=None, group=None, inherit=False):
@@ -816,10 +860,10 @@ class CadfNotificationsWrapperTestCase(test_v3.RestfulTestCase):
self.assertEqual(project, event.project)
if domain:
self.assertEqual(domain, event.domain)
- if user:
- self.assertEqual(user, event.user)
if group:
self.assertEqual(group, event.group)
+ elif user:
+ self.assertEqual(user, event.user)
self.assertEqual(role_id, event.role)
self.assertEqual(inherit, event.inherited_to_projects)
@@ -857,12 +901,16 @@ class CadfNotificationsWrapperTestCase(test_v3.RestfulTestCase):
user=None, group=None):
self.put(url)
action = "%s.%s" % (CREATED_OPERATION, self.ROLE_ASSIGNMENT)
- self._assert_last_note(action, self.user_id)
+ event_type = '%s.%s.%s' % (notifications.SERVICE,
+ self.ROLE_ASSIGNMENT, CREATED_OPERATION)
+ self._assert_last_note(action, self.user_id, event_type)
self._assert_event(role, project, domain, user, group)
self.delete(url)
action = "%s.%s" % (DELETED_OPERATION, self.ROLE_ASSIGNMENT)
- self._assert_last_note(action, self.user_id)
- self._assert_event(role, project, domain, user, group)
+ event_type = '%s.%s.%s' % (notifications.SERVICE,
+ self.ROLE_ASSIGNMENT, DELETED_OPERATION)
+ self._assert_last_note(action, self.user_id, event_type)
+ self._assert_event(role, project, domain, user, None)
def test_user_project_grant(self):
url = ('/projects/%s/users/%s/roles/%s' %
@@ -874,14 +922,50 @@ class CadfNotificationsWrapperTestCase(test_v3.RestfulTestCase):
def test_group_domain_grant(self):
group_ref = self.new_group_ref(domain_id=self.domain_id)
group = self.identity_api.create_group(group_ref)
+ self.identity_api.add_user_to_group(self.user_id, group['id'])
url = ('/domains/%s/groups/%s/roles/%s' %
(self.domain_id, group['id'], self.role_id))
self._test_role_assignment(url, self.role_id,
domain=self.domain_id,
+ user=self.user_id,
group=group['id'])
+ def test_add_role_to_user_and_project(self):
+ # A notification is sent when add_role_to_user_and_project is called on
+ # the assignment manager.
+
+ project_ref = self.new_project_ref(self.domain_id)
+ project = self.resource_api.create_project(
+ project_ref['id'], project_ref)
+ tenant_id = project['id']
+
+ self.assignment_api.add_role_to_user_and_project(
+ self.user_id, tenant_id, self.role_id)
+
+ self.assertTrue(self._notifications)
+ note = self._notifications[-1]
+ self.assertEqual(note['action'], 'created.role_assignment')
+ self.assertTrue(note['send_notification_called'])
+
+ self._assert_event(self.role_id, project=tenant_id, user=self.user_id)
+
+ def test_remove_role_from_user_and_project(self):
+ # A notification is sent when remove_role_from_user_and_project is
+ # called on the assignment manager.
+
+ self.assignment_api.remove_role_from_user_and_project(
+ self.user_id, self.project_id, self.role_id)
+
+ self.assertTrue(self._notifications)
+ note = self._notifications[-1]
+ self.assertEqual(note['action'], 'deleted.role_assignment')
+ self.assertTrue(note['send_notification_called'])
+
+ self._assert_event(self.role_id, project=self.project_id,
+ user=self.user_id)
+
-class TestCallbackRegistration(testtools.TestCase):
+class TestCallbackRegistration(unit.BaseTestCase):
def setUp(self):
super(TestCallbackRegistration, self).setUp()
self.mock_log = mock.Mock()
diff --git a/keystone-moon/keystone/tests/unit/common/test_utils.py b/keystone-moon/keystone/tests/unit/common/test_utils.py
index 184c8141..e8bac3c0 100644
--- a/keystone-moon/keystone/tests/unit/common/test_utils.py
+++ b/keystone-moon/keystone/tests/unit/common/test_utils.py
@@ -150,7 +150,7 @@ class UtilsTestCase(tests.BaseTestCase):
def test_pki_encoder(self):
data = {'field': 'value'}
json = jsonutils.dumps(data, cls=common_utils.PKIEncoder)
- expected_json = b'{"field":"value"}'
+ expected_json = '{"field":"value"}'
self.assertEqual(expected_json, json)