Add unit tests
This commit is contained in:
parent
4e1cca4895
commit
1fd2dd072c
6
.travis.yml
Normal file
6
.travis.yml
Normal file
@ -0,0 +1,6 @@
|
||||
language: python
|
||||
python:
|
||||
- "3.6"
|
||||
install: pip install tox-travis
|
||||
script:
|
||||
- tox -e pep8,py3
|
@ -1,4 +1,4 @@
|
||||
# Copyright 2016 Canonical Ltd
|
||||
# Copyright 2019 Canonical Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -16,7 +16,15 @@ import sys
|
||||
|
||||
sys.path.append('src')
|
||||
sys.path.append('src/lib')
|
||||
sys.path.append('src/actions')
|
||||
|
||||
# Mock out charmhelpers so that we can test without it.
|
||||
import charms_openstack.test_mocks # noqa
|
||||
charms_openstack.test_mocks.mock_charmhelpers()
|
||||
|
||||
import mock
|
||||
import charms
|
||||
keystoneauth1 = mock.MagicMock()
|
||||
sys.modules['keystoneauth1'] = keystoneauth1
|
||||
charms.leadership = mock.MagicMock()
|
||||
sys.modules['charms.leadership'] = charms.leadership
|
||||
|
62
unit_tests/test_actions.py
Normal file
62
unit_tests/test_actions.py
Normal file
@ -0,0 +1,62 @@
|
||||
# Copyright 2019 Canonical Ltd
|
||||
#
|
||||
# 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.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import mock
|
||||
|
||||
import charms_openstack.test_utils as test_utils
|
||||
|
||||
import actions
|
||||
|
||||
|
||||
class TestKeystoneSAMLMellonActions(test_utils.PatchHelper):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.patch_object(actions.hookenv, 'action_set')
|
||||
self.patch_object(actions.hookenv, 'action_fail')
|
||||
self.patch_object(actions, "os")
|
||||
|
||||
self.patch(
|
||||
"builtins.open", new_callable=mock.mock_open(), name="open")
|
||||
self.file = mock.MagicMock()
|
||||
self.fileobj = mock.MagicMock()
|
||||
self.fileobj.__enter__.return_value = self.file
|
||||
self.open.return_value = self.fileobj
|
||||
|
||||
def test_get_sp_metadata(self):
|
||||
# Valid XML
|
||||
self.sp_metadata_xml = (
|
||||
"<?xml version='1.0' encoding='UTF-8'?>"
|
||||
"<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>"
|
||||
"<ds:X509Data> <ds:X509Certificate> </ds:X509Certificate>"
|
||||
"</ds:X509Data> </ds:KeyInfo>")
|
||||
self.file.readlines.return_value = self.sp_metadata_xml
|
||||
self.metadata_file = ("/etc/apache2/mellon/"
|
||||
"sp-meta.keystone-saml-mellon.xml")
|
||||
|
||||
# File Does not exist
|
||||
self.os.path.exists.return_value = False
|
||||
actions.get_sp_metadata()
|
||||
self.action_fail.assert_called_once_with(
|
||||
"The SP metadata file {} does not exist"
|
||||
.format(self.metadata_file))
|
||||
|
||||
# File exists
|
||||
self.os.path.exists.return_value = True
|
||||
actions.get_sp_metadata()
|
||||
self.action_set.assert_called_once_with(
|
||||
{"output": self.sp_metadata_xml})
|
151
unit_tests/test_keystone_saml_mellon_handlers.py
Normal file
151
unit_tests/test_keystone_saml_mellon_handlers.py
Normal file
@ -0,0 +1,151 @@
|
||||
# Copyright 2019 Canonical Ltd
|
||||
#
|
||||
# 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.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import mock
|
||||
|
||||
import charm.openstack.keystone_saml_mellon as keystone_saml_mellon
|
||||
import reactive.keystone_saml_mellon_handlers as handlers
|
||||
|
||||
import charms_openstack.test_utils as test_utils
|
||||
|
||||
|
||||
class TestRegisteredHooks(test_utils.TestRegisteredHooks):
|
||||
|
||||
def test_hooks(self):
|
||||
defaults = [
|
||||
'charm.installed',
|
||||
'update-status']
|
||||
hook_set = {
|
||||
'hook': {
|
||||
'default_upgrade_charm': ('upgrade-charm',),
|
||||
},
|
||||
'when': {
|
||||
'render_config': (
|
||||
'endpoint.keystone-fid-service-provider.joined',
|
||||
'config.complete',
|
||||
'keystone-data.complete',),
|
||||
'config_changed': (
|
||||
'endpoint.keystone-fid-service-provider.joined',),
|
||||
'keystone_data_changed': (
|
||||
'endpoint.keystone-fid-service-provider.joined',),
|
||||
'configure_websso': (
|
||||
'endpoint.websso-fid-service-provider.joined',
|
||||
'config.complete',
|
||||
'keystone-data.complete',
|
||||
'config.rendered',),
|
||||
},
|
||||
'when_not': {
|
||||
'config_changed': ('config.complete',),
|
||||
'keystone_departed': (
|
||||
'endpoint.keystone-fid-service-provider.joined',),
|
||||
'keystone_data_changed': ('keystone-data.complete',),
|
||||
'render_config': ('config.rendered',),
|
||||
'assess_status': ('always.run',),
|
||||
},
|
||||
}
|
||||
# test that the hooks were registered via the
|
||||
# reactive.keystone_saml_mellon_handlers
|
||||
self.registered_hooks_test_helper(handlers, hook_set, defaults)
|
||||
|
||||
|
||||
class TestKeystoneSAMLMellonHandlers(test_utils.PatchHelper):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.patch_release(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonCharm.release)
|
||||
self.keystone_saml_mellon_charm = mock.MagicMock()
|
||||
self.patch_object(handlers.charm, 'provide_charm_instance',
|
||||
new=mock.MagicMock())
|
||||
self.provide_charm_instance().__enter__.return_value = (
|
||||
self.keystone_saml_mellon_charm)
|
||||
self.provide_charm_instance().__exit__.return_value = None
|
||||
|
||||
self.patch_object(handlers, 'flags')
|
||||
|
||||
self.uuid = 'uuid-uuid'
|
||||
self.patch_object(handlers.uuid, 'uuid4')
|
||||
self.uuid4.return_value = self.uuid
|
||||
|
||||
self.patch_object(handlers, 'unitdata',
|
||||
new=mock.MagicMock())
|
||||
self.kv = mock.MagicMock()
|
||||
self.unitdata.kv.return_value = self.kv
|
||||
|
||||
self.patch_object(handlers, 'endpoint_from_flag',
|
||||
new=mock.MagicMock())
|
||||
self.endpoint = mock.MagicMock()
|
||||
self.endpoint_from_flag.return_value = self.endpoint
|
||||
|
||||
self.protocol_name = "mapped"
|
||||
self.remote_id_attribute = "https://samltest.id"
|
||||
self.idp_name = "samltest"
|
||||
self.user_facing_name = "samltest.id"
|
||||
self.keystone_saml_mellon_charm.options.protocol_name = (
|
||||
self.protocol_name)
|
||||
self.keystone_saml_mellon_charm.options.remote_id_attribute = (
|
||||
self.remote_id_attribute)
|
||||
self.keystone_saml_mellon_charm.options.idp_name = self.idp_name
|
||||
self.keystone_saml_mellon_charm.options.user_facing_name = (
|
||||
self.user_facing_name)
|
||||
|
||||
self.all_joined_units = []
|
||||
for i in range(0, 2):
|
||||
unit = mock.MagicMock()
|
||||
unit.name = "keystone-{}".format(i)
|
||||
unit.recieved = {"hostname": unit.name,
|
||||
"port": "5000",
|
||||
"tls-enabled": True}
|
||||
self.all_joined_units.append(unit)
|
||||
|
||||
def test_keystone_departed(self):
|
||||
handlers.keystone_departed()
|
||||
self.keystone_saml_mellon_charm.remove_config.assert_called_once_with()
|
||||
|
||||
def test_keystone_data_changed(self):
|
||||
kv_set_calls = [
|
||||
mock.call("tls-enabled", True),
|
||||
mock.call("port", "5000"),
|
||||
mock.call("hostname", "keystone-0"),
|
||||
]
|
||||
|
||||
handlers.keystone_data_changed(self.endpoint)
|
||||
|
||||
self.kv.set.has_calls(kv_set_calls)
|
||||
self.flags.set_flag.assert_called_once_with('keystone-data.complete')
|
||||
|
||||
def test_render_config(self):
|
||||
handlers.render_config()
|
||||
self.keystone_saml_mellon_charm.render_config.assert_called_once_with()
|
||||
self.flags.set_flag.assert_called_once_with('config.rendered')
|
||||
self.endpoint.publish.assert_called_once_with(
|
||||
self.uuid, self.protocol_name, self.remote_id_attribute)
|
||||
|
||||
def test_config_changed(self):
|
||||
handlers.config_changed()
|
||||
(self.keystone_saml_mellon_charm.configuration_complete
|
||||
.return_value) = True
|
||||
self.flags.set_flag.assert_called_once_with('config.complete')
|
||||
|
||||
def test_configure_websso(self):
|
||||
handlers.configure_websso()
|
||||
self.endpoint.publish.assert_called_once_with(
|
||||
self.protocol_name, self.idp_name, self.user_facing_name)
|
||||
|
||||
def test_assess_status(self):
|
||||
handlers.assess_status()
|
||||
self.keystone_saml_mellon_charm.assess_status.assert_called_once_with()
|
378
unit_tests/test_lib_charm_openstack_keystone_saml_mellon.py
Normal file
378
unit_tests/test_lib_charm_openstack_keystone_saml_mellon.py
Normal file
@ -0,0 +1,378 @@
|
||||
# Copyright 2019 Canonical Ltd
|
||||
#
|
||||
# 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.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import mock
|
||||
|
||||
import charms_openstack.test_utils as test_utils
|
||||
|
||||
import charm.openstack.keystone_saml_mellon as keystone_saml_mellon
|
||||
|
||||
|
||||
def FakeConfig(init_dict):
|
||||
|
||||
def _config(key=None):
|
||||
return init_dict[key] if key else init_dict
|
||||
|
||||
return _config
|
||||
|
||||
|
||||
def FakeResourceGet(init_dict):
|
||||
|
||||
def _config(key=None):
|
||||
return init_dict[key] if key else init_dict
|
||||
|
||||
return _config
|
||||
|
||||
|
||||
class Helper(test_utils.PatchHelper):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.patch_release(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonCharm.release)
|
||||
|
||||
self.patch_object(keystone_saml_mellon, 'unitdata',
|
||||
new=mock.MagicMock())
|
||||
self.kv = mock.MagicMock()
|
||||
self.unitdata.kv.return_value = self.kv
|
||||
|
||||
self.patch_object(keystone_saml_mellon.os_utils, 'os_release',
|
||||
new=mock.MagicMock())
|
||||
|
||||
self.idp_name = "samltest"
|
||||
self.protocol_name = "mapped"
|
||||
self.user_facing_name = "samltest.id"
|
||||
self.nameid_formats = "fake:name:id:format1,fake:name:id:format2"
|
||||
self.test_config = {
|
||||
"idp-name": self.idp_name,
|
||||
"protocol-name": self.protocol_name,
|
||||
"user-facing-name": self.user_facing_name,
|
||||
"nameid-formats": self.nameid_formats,
|
||||
"subject-confirmation-data-address-check": False
|
||||
}
|
||||
self.resources = {
|
||||
"idp-metadata": "/path/to/idp-metadata.xml",
|
||||
"sp-private-key": "/path/to/sp-private-key.pem",
|
||||
"sp-signing-keyinfo": "/path/to/sp-signing-keyinfo.xml"
|
||||
}
|
||||
self.patch_object(keystone_saml_mellon.hookenv, 'config',
|
||||
side_effect=FakeConfig(self.test_config))
|
||||
self.patch_object(keystone_saml_mellon.hookenv, 'resource_get',
|
||||
side_effect=FakeResourceGet(self.resources))
|
||||
self.patch_object(
|
||||
keystone_saml_mellon.hookenv, 'application_version_set')
|
||||
self.patch_object(keystone_saml_mellon.hookenv, 'status_set')
|
||||
self.patch_object(keystone_saml_mellon.ch_host, 'mkdir')
|
||||
self.patch_object(keystone_saml_mellon.core.templating, 'render')
|
||||
|
||||
self.template_loader = mock.MagicMock()
|
||||
self.patch_object(keystone_saml_mellon.os_templating, 'get_loader',
|
||||
return_value=self.template_loader)
|
||||
self.patch_object(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonCharm,
|
||||
'application_version',
|
||||
return_value="1.0.0")
|
||||
|
||||
self.patch_object(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonCharm, 'render_configs')
|
||||
self.patch_object(keystone_saml_mellon, 'os')
|
||||
self.patch_object(keystone_saml_mellon, 'subprocess')
|
||||
|
||||
self.patch(
|
||||
"builtins.open", new_callable=mock.mock_open(), name="open")
|
||||
self.file = mock.MagicMock()
|
||||
self.fileobj = mock.MagicMock()
|
||||
self.fileobj.__enter__.return_value = self.file
|
||||
self.open.return_value = self.fileobj
|
||||
|
||||
|
||||
class TestKeystoneSAMLMellonUtils(Helper):
|
||||
|
||||
def test_select_release(self):
|
||||
self.kv.get.return_value = 'mitaka'
|
||||
self.assertEqual(
|
||||
keystone_saml_mellon.select_release(), 'mitaka')
|
||||
|
||||
self.kv.get.return_value = None
|
||||
self.os_release.return_value = 'rocky'
|
||||
self.assertEqual(
|
||||
keystone_saml_mellon.select_release(), 'rocky')
|
||||
|
||||
|
||||
class TestKeystoneSAMLMellonConfigurationAdapter(Helper):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.hostname = "keystone-sp.local"
|
||||
self.port = "5000"
|
||||
self.tls_enabled = True
|
||||
self.unitdata_data = {
|
||||
"hostname": self.hostname,
|
||||
"port": self.port,
|
||||
"tls-enabled": self.tls_enabled,
|
||||
}
|
||||
self.kv.get.side_effect = FakeConfig(self.unitdata_data)
|
||||
self.base_url = "https://{}:{}".format(self.hostname, self.port)
|
||||
|
||||
def test_validation_errors(self):
|
||||
errors = {"idp-metadata": "Bad XML"}
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
ksmca._validation_errors = errors
|
||||
self.assertEqual(ksmca.validation_errors, errors)
|
||||
|
||||
def test_remote_id_attribute(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(ksmca.remote_id_attribute, "MELLON_IDP")
|
||||
|
||||
def test_idp_metadata_file(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.idp_metadata_file, keystone_saml_mellon.IDP_METADATA)
|
||||
|
||||
def test_sp_metadata_file(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_metadata_file, keystone_saml_mellon.SP_METADATA)
|
||||
|
||||
def test_sp_private_key_file(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_private_key_file, keystone_saml_mellon.SP_PRIVATE_KEY)
|
||||
|
||||
def test_keystone_host(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(ksmca.keystone_host, self.hostname)
|
||||
|
||||
def test_keystone_port(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(ksmca.keystone_port, self.port)
|
||||
|
||||
def test_keystone_tls_enabled(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(ksmca.tls_enabled, self.tls_enabled)
|
||||
|
||||
def test_keystone_base_url(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(ksmca.keystone_base_url, self.base_url)
|
||||
|
||||
def test_sp_idp_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_idp_path,
|
||||
'/v3/OS-FEDERATION/identity_providers/{}'.format(self.idp_name))
|
||||
|
||||
def test_sp_protocol_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_protocol_path,
|
||||
'{}/protocols/{}'.format(ksmca.sp_idp_path, self.protocol_name))
|
||||
|
||||
def test_sp_auth_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_auth_path, '{}/auth'.format(ksmca.sp_protocol_path))
|
||||
|
||||
def test_mellon_endpoint_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.mellon_endpoint_path, '{}/mellon'.format(ksmca.sp_auth_path))
|
||||
|
||||
def test_websso_auth_idp_protocol_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.websso_auth_idp_protocol_path,
|
||||
('/v3/auth/OS-FEDERATION/identity_providers/{}/protocols/{}/websso'
|
||||
.format(self.idp_name, self.protocol_name)))
|
||||
|
||||
def test_sp_post_response_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_post_response_path,
|
||||
'{}/postResponse'.format(ksmca.mellon_endpoint_path))
|
||||
|
||||
def test_sp_logout_path(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_logout_path,
|
||||
'{}/logout'.format(ksmca.mellon_endpoint_path))
|
||||
|
||||
def test_sp_auth_url(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_auth_url,
|
||||
'{}{}'.format(ksmca.keystone_base_url, ksmca.sp_auth_path))
|
||||
|
||||
def test_sp_logout_url(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_logout_url,
|
||||
'{}{}'.format(ksmca.keystone_base_url, ksmca.sp_logout_path))
|
||||
|
||||
def test_sp_post_response_url(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.sp_post_response_url,
|
||||
'{}{}'.format(ksmca.keystone_base_url,
|
||||
ksmca.sp_post_response_path))
|
||||
|
||||
def test_mellon_subject_confirmation_data_address_check(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.mellon_subject_confirmation_data_address_check,
|
||||
'Off')
|
||||
|
||||
def test_supported_nameid_formats(self):
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
self.assertEqual(
|
||||
ksmca.supported_nameid_formats, self.nameid_formats.split(","))
|
||||
|
||||
def test_idp_metadata(self):
|
||||
self.os.path.exists.return_value = True
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
# Valid XML
|
||||
self.idp_metadata_xml = (
|
||||
"<?xml version='1.0' encoding='UTF-8'?>"
|
||||
"<EntityDescriptor entityID='https://samltest.id/saml/idp'> "
|
||||
"</EntityDescriptor>")
|
||||
self.file.read.return_value = self.idp_metadata_xml
|
||||
self.assertEqual(ksmca.idp_metadata, self.idp_metadata_xml)
|
||||
self.open.assert_called_with(self.resources["idp-metadata"])
|
||||
|
||||
# Inalid XML
|
||||
ksmca._idp_metadata = None
|
||||
self.file.read.return_value = "INVALID XML"
|
||||
self.assertEqual(ksmca.idp_metadata, "")
|
||||
self.assertEqual(
|
||||
ksmca._validation_errors,
|
||||
{"idp-metadata": ksmca.IDP_METADATA_INVALID})
|
||||
|
||||
def test_sp_signing_keyinfo(self):
|
||||
self.os.path.exists.return_value = True
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
# Valid XML
|
||||
self.sp_signing_keyinfo_xml = (
|
||||
"<?xml version='1.0' encoding='UTF-8'?>"
|
||||
"<ds:KeyInfo xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>"
|
||||
"<ds:X509Data> <ds:X509Certificate> </ds:X509Certificate>"
|
||||
"</ds:X509Data> </ds:KeyInfo>")
|
||||
self.file.read.return_value = self.sp_signing_keyinfo_xml
|
||||
self.assertEqual(ksmca.sp_signing_keyinfo, self.sp_signing_keyinfo_xml)
|
||||
self.open.assert_called_with(self.resources["sp-signing-keyinfo"])
|
||||
|
||||
# Inalid XML
|
||||
ksmca._sp_signing_keyinfo = None
|
||||
self.file.read.return_value = "INVALID XML"
|
||||
self.assertEqual(ksmca.sp_signing_keyinfo, "")
|
||||
self.assertEqual(
|
||||
ksmca._validation_errors,
|
||||
{"sp-signing-keyinfo": ksmca.SP_SIGNING_KEYINFO_INVALID})
|
||||
|
||||
def test_sp_private_key(self):
|
||||
self.os.path.exists.return_value = True
|
||||
ksmca = keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter()
|
||||
# Valid Key
|
||||
self.sp_private_key_pem = ("""
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBPAIBAAJBANLUtlT9JMQ/RcGEipW6MBtUoFBGMOclUmOpP1BbaFJoBn19J0UG
|
||||
STj29M9nDLDRdfP0O/JiisG6ejxmO0A0xTsCAwEAAQJBAKT0IKRmW3ngN2etl/CF
|
||||
+FWp5LRp9qEjJk8rgIoSupCdvuT0Q6XLk/ygHeiBYcKTf2pT/PWjQxg1pD7So5K8
|
||||
YcECIQD5SKfItJ5YC9mD+6H28UqQATPehRPhQEEFIl/lJCrFgwIhANiC14XvcuWc
|
||||
xMy1Lcc5lFkrB+b+oWVKJyMpNTHgXivpAiEAqh0FurZfNDBp8GJgpbcFrf3UGq7v
|
||||
4RBLDqjljeY/decCIEk3/lDCCFYULQ2ZW9Da7Qs2nSaGB+isKg4e+mlSmiY5AiEA
|
||||
lAoUNjDHWBOlyXziqZiufMURqbPPbRkEjWwN8G2r15A=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
""")
|
||||
self.file.read.return_value = self.sp_private_key_pem
|
||||
self.assertEqual(ksmca.sp_private_key, self.sp_private_key_pem)
|
||||
self.open.assert_called_with(self.resources["sp-private-key"])
|
||||
|
||||
# Invalid Key
|
||||
ksmca._sp_private_key = None
|
||||
self.file.read.return_value = "INVALID PEM KEY"
|
||||
self.assertEqual(ksmca.sp_private_key, '')
|
||||
self.assertEqual(
|
||||
ksmca._validation_errors,
|
||||
{"sp-private-key": ksmca.SP_PRIVATE_KEY_INVALID})
|
||||
|
||||
|
||||
class TestKeystoneSAMLMellonCharm(Helper):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.patch_object(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter,
|
||||
'idp_metadata')
|
||||
self.patch_object(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter,
|
||||
'sp_private_key')
|
||||
self.patch_object(
|
||||
keystone_saml_mellon.KeystoneSAMLMellonConfigurationAdapter,
|
||||
'sp_signing_keyinfo')
|
||||
self.idp_metadata.return_value = self.resources["idp-metadata"]
|
||||
self.idp_metadata.__bool__.return_value = True
|
||||
self.sp_private_key.return_value = self.resources["sp-private-key"]
|
||||
self.sp_private_key.__bool__.return_value = True
|
||||
self.sp_signing_keyinfo.return_value = self.resources[
|
||||
"sp-signing-keyinfo"]
|
||||
self.sp_signing_keyinfo.__bool__.return_value = True
|
||||
|
||||
def test_configuration_complete(self):
|
||||
ksm = keystone_saml_mellon.KeystoneSAMLMellonCharm()
|
||||
self.assertTrue(ksm.configuration_complete())
|
||||
|
||||
# One option not ready
|
||||
self.sp_signing_keyinfo.__bool__.return_value = False
|
||||
self.assertFalse(ksm.configuration_complete())
|
||||
|
||||
def test_assess_status(self):
|
||||
ksm = keystone_saml_mellon.KeystoneSAMLMellonCharm()
|
||||
ksm.assess_status()
|
||||
self.application_version_set.asert_called_once_with()
|
||||
self.status_set.assert_called_once_with("active", "Unit is ready")
|
||||
|
||||
# One option not ready
|
||||
self.status_set.reset_mock()
|
||||
self.sp_signing_keyinfo.__bool__.return_value = False
|
||||
ksm.options._validation_errors = {"idp-metadata": "malformed"}
|
||||
ksm.assess_status()
|
||||
self.status_set.assert_called_once_with(
|
||||
"blocked", "Configuration is incomplete. idp-metadata: malformed")
|
||||
|
||||
def test_render_config(self):
|
||||
ksm = keystone_saml_mellon.KeystoneSAMLMellonCharm()
|
||||
ksm.render_config()
|
||||
self.assertEqual(self.render_configs.call_count, 1)
|
||||
self.assertEqual(self.render.call_count, 2)
|
||||
|
||||
def test_remove_config(self):
|
||||
self.os.path.exists.return_value = True
|
||||
ksm = keystone_saml_mellon.KeystoneSAMLMellonCharm()
|
||||
ksm.remove_config()
|
||||
self.assertEqual(self.os.path.exists.call_count, 4)
|
||||
self.assertEqual(self.os.unlink.call_count, 4)
|
||||
|
||||
def test_enable_module(self):
|
||||
ksm = keystone_saml_mellon.KeystoneSAMLMellonCharm()
|
||||
ksm.enable_module()
|
||||
self.subprocess.check_call.assert_called_once_with(
|
||||
['a2enmod', 'auth_mellon'])
|
||||
|
||||
def test_disable_module(self):
|
||||
ksm = keystone_saml_mellon.KeystoneSAMLMellonCharm()
|
||||
ksm.disable_module()
|
||||
self.subprocess.check_call.assert_called_once_with(
|
||||
['a2dismod', 'auth_mellon'])
|
Loading…
Reference in New Issue
Block a user