Overall refresh to current install from source approach
This commit is contained in:
parent
c2aa14e89d
commit
d5e9cebd14
7
Makefile
7
Makefile
@ -2,7 +2,7 @@
|
||||
PYTHON := /usr/bin/env python
|
||||
|
||||
lint:
|
||||
@flake8 --exclude hooks/charmhelpers hooks unit_tests tests
|
||||
@flake8 --exclude hooks/charmhelpers actions hooks unit_tests tests
|
||||
@charm proof
|
||||
|
||||
unit_test:
|
||||
@ -15,7 +15,7 @@ bin/charm_helpers_sync.py:
|
||||
> bin/charm_helpers_sync.py
|
||||
|
||||
sync: bin/charm_helpers_sync.py
|
||||
@$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-sync.yaml
|
||||
@$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml
|
||||
@$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-tests.yaml
|
||||
|
||||
test:
|
||||
@ -25,7 +25,8 @@ test:
|
||||
# https://bugs.launchpad.net/amulet/+bug/1320357
|
||||
@juju test -v -p AMULET_HTTP_PROXY --timeout 900 \
|
||||
00-setup 14-basic-precise-icehouse 15-basic-trusty-icehouse \
|
||||
16-basic-trusty-juno
|
||||
16-basic-trusty-icehouse-git 17-basic-trusty-juno \
|
||||
18-basic-trusty-juno-git
|
||||
|
||||
publish: lint unit_test
|
||||
bzr push lp:charms/neutron-openvswitch
|
||||
|
166
README.md
166
README.md
@ -44,95 +44,87 @@ These compute nodes could then be accessed by cloud users via use of host aggreg
|
||||
|
||||
# Deploying from source
|
||||
|
||||
The minimal openstack-origin-git config required to deploy from source is:
|
||||
The minimum openstack-origin-git config required to deploy from source is:
|
||||
|
||||
openstack-origin-git:
|
||||
"{'neutron':
|
||||
{'repository': 'git://git.openstack.org/openstack/neutron.git',
|
||||
'branch': 'stable/icehouse'}}"
|
||||
"repositories:
|
||||
- {name: requirements,
|
||||
repository: 'git://git.openstack.org/openstack/requirements',
|
||||
branch: stable/juno}
|
||||
- {name: neutron,
|
||||
repository: 'git://git.openstack.org/openstack/neutron',
|
||||
branch: stable/juno}"
|
||||
|
||||
If you specify a 'requirements' repository, it will be used to update the
|
||||
requirements.txt files of all other git repos that it applies to, before
|
||||
they are installed:
|
||||
Note that there are only two 'name' values the charm knows about: 'requirements'
|
||||
and 'neutron'. These repositories must correspond to these 'name' values.
|
||||
Additionally, the requirements repository must be specified first and the
|
||||
neutron repository must be specified last. All other repostories are installed
|
||||
in the order in which they are specified.
|
||||
|
||||
The following is a full list of current tip repos (may not be up-to-date):
|
||||
|
||||
openstack-origin-git:
|
||||
"{'requirements':
|
||||
{'repository': 'git://git.openstack.org/openstack/requirements.git',
|
||||
'branch': 'master'},
|
||||
'neutron':
|
||||
{'repository': 'git://git.openstack.org/openstack/neutron.git',
|
||||
'branch': 'master'}}"
|
||||
|
||||
Note that there are only two key values the charm knows about for the outermost
|
||||
dictionary: 'neutron' and 'requirements'. These repositories must correspond to
|
||||
these keys. If the requirements repository is specified, it will be installed
|
||||
first. The neutron repository is always installed last. All other repostories
|
||||
will be installed in between.
|
||||
|
||||
NOTE(coreycb): The following is temporary to keep track of the full list of
|
||||
current tip repos (may not be up-to-date).
|
||||
|
||||
openstack-origin-git:
|
||||
"{'requirements':
|
||||
{'repository': 'git://git.openstack.org/openstack/requirements.git',
|
||||
'branch': 'master'},
|
||||
'neutron-fwaas':
|
||||
{'repository': 'git://git.openstack.org/openstack/neutron-fwaas.git',
|
||||
'branch': 'master'},
|
||||
'neutron-lbaas':
|
||||
{'repository: 'git://git.openstack.org/openstack/neutron-lbaas.git',
|
||||
'branch': 'master'},
|
||||
'neutron-vpnaas':
|
||||
{'repository: 'git://git.openstack.org/openstack/neutron-vpnaas.git',
|
||||
'branch': 'master'},
|
||||
'keystonemiddleware:
|
||||
{'repository': 'git://git.openstack.org/openstack/keystonemiddleware.git',
|
||||
'branch: 'master'},
|
||||
'oslo-concurrency':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.concurrency.git',
|
||||
'branch: 'master'},
|
||||
'oslo-config':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.config.git',
|
||||
'branch: 'master'},
|
||||
'oslo-context':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.context.git',
|
||||
'branch: 'master'},
|
||||
'oslo-db':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.db.git',
|
||||
'branch: 'master'},
|
||||
'oslo-i18n':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.i18n.git',
|
||||
'branch: 'master'},
|
||||
'oslo-messaging':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.messaging.git',
|
||||
'branch: 'master'},
|
||||
'oslo-middleware:
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.middleware.git',
|
||||
'branch': 'master'},
|
||||
'oslo-rootwrap':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.rootwrap.git',
|
||||
'branch: 'master'},
|
||||
'oslo-serialization':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.serialization.git',
|
||||
'branch: 'master'},
|
||||
'oslo-utils':
|
||||
{'repository': 'git://git.openstack.org/openstack/oslo.utils.git',
|
||||
'branch: 'master'},
|
||||
'pbr':
|
||||
{'repository': 'git://git.openstack.org/openstack-dev/pbr.git',
|
||||
'branch: 'master'},
|
||||
'python-keystoneclient':
|
||||
{'repository': 'git://git.openstack.org/openstack/python-keystoneclient.git',
|
||||
'branch: 'master'},
|
||||
'python-neutronclient':
|
||||
{'repository': 'git://git.openstack.org/openstack/python-neutronclient.git',
|
||||
'branch: 'master'},
|
||||
'python-novaclient':
|
||||
{'repository': 'git://git.openstack.org/openstack/python-novaclient.git',
|
||||
'branch: 'master'},
|
||||
'stevedore':
|
||||
{'repository': 'git://git.openstack.org/openstack/stevedore.git',
|
||||
'branch: 'master'},
|
||||
'neutron':
|
||||
{'repository': 'git://git.openstack.org/openstack/neutron.git',
|
||||
'branch': 'master'}}"
|
||||
"repositories:
|
||||
- {name: requirements,
|
||||
repository: 'git://git.openstack.org/openstack/requirements',
|
||||
branch: master}
|
||||
- {name: oslo-concurrency,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.concurrency',
|
||||
branch: master}
|
||||
- {name: oslo-config,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.config',
|
||||
branch: master}
|
||||
- {name: oslo-context,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.context.git',
|
||||
branch: master}
|
||||
- {name: oslo-db,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.db',
|
||||
branch: master}
|
||||
- {name: oslo-i18n,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.i18n',
|
||||
branch: master}
|
||||
- {name: oslo-messaging,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.messaging.git',
|
||||
branch: master}
|
||||
- {name: oslo-middleware,
|
||||
repository': 'git://git.openstack.org/openstack/oslo.middleware.git',
|
||||
branch: master}
|
||||
- {name: oslo-rootwrap',
|
||||
repository: 'git://git.openstack.org/openstack/oslo.rootwrap.git',
|
||||
branch: master}
|
||||
- {name: oslo-serialization,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.serialization',
|
||||
branch: master}
|
||||
- {name: oslo-utils,
|
||||
repository: 'git://git.openstack.org/openstack/oslo.utils',
|
||||
branch: master}
|
||||
- {name: pbr,
|
||||
repository: 'git://git.openstack.org/openstack-dev/pbr',
|
||||
branch: master}
|
||||
- {name: stevedore,
|
||||
repository: 'git://git.openstack.org/openstack/stevedore.git',
|
||||
branch: 'master'}
|
||||
- {name: python-keystoneclient,
|
||||
repository: 'git://git.openstack.org/openstack/python-keystoneclient',
|
||||
branch: master}
|
||||
- {name: python-neutronclient,
|
||||
repository: 'git://git.openstack.org/openstack/python-neutronclient.git',
|
||||
branch: master}
|
||||
- {name: python-novaclient,
|
||||
repository': 'git://git.openstack.org/openstack/python-novaclient.git',
|
||||
branch: master}
|
||||
- {name: keystonemiddleware,
|
||||
repository: 'git://git.openstack.org/openstack/keystonemiddleware',
|
||||
branch: master}
|
||||
- {name: neutron-fwaas,
|
||||
repository': 'git://git.openstack.org/openstack/neutron-fwaas.git',
|
||||
branch: master}
|
||||
- {name: neutron-lbaas,
|
||||
repository: 'git://git.openstack.org/openstack/neutron-lbaas.git',
|
||||
branch: master}
|
||||
- {name: neutron-vpnaas,
|
||||
repository: 'git://git.openstack.org/openstack/neutron-vpnaas.git',
|
||||
branch: master}
|
||||
- {name: neutron,
|
||||
repository: 'git://git.openstack.org/openstack/neutron',
|
||||
branch: master}"
|
||||
|
2
actions.yaml
Normal file
2
actions.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
git-reinstall:
|
||||
description: Reinstall neutron-openvswitch from the openstack-origin-git repositories.
|
1
actions/git-reinstall
Symbolic link
1
actions/git-reinstall
Symbolic link
@ -0,0 +1 @@
|
||||
git_reinstall.py
|
40
actions/git_reinstall.py
Executable file
40
actions/git_reinstall.py
Executable file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
sys.path.append('hooks/')
|
||||
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
git_install_requested,
|
||||
)
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
action_set,
|
||||
action_fail,
|
||||
config,
|
||||
)
|
||||
|
||||
from neutron_ovs_utils import (
|
||||
git_install,
|
||||
)
|
||||
|
||||
|
||||
def git_reinstall():
|
||||
"""Reinstall from source and restart services.
|
||||
|
||||
If the openstack-origin-git config option was used to install openstack
|
||||
from source git repositories, then this action can be used to reinstall
|
||||
from updated git repositories, followed by a restart of services."""
|
||||
if not git_install_requested():
|
||||
action_fail('openstack-origin-git is not configured')
|
||||
return
|
||||
|
||||
try:
|
||||
git_install(config('openstack-origin-git'))
|
||||
except:
|
||||
action_set({'traceback': traceback.format_exc()})
|
||||
action_fail('git-reinstall resulted in an unexpected error')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
git_reinstall()
|
@ -1,5 +1,4 @@
|
||||
#branch: lp:charm-helpers
|
||||
branch: /home/corey/src/charms/git/charm-helpers
|
||||
branch: lp:charm-helpers
|
||||
destination: hooks/charmhelpers
|
||||
include:
|
||||
- core
|
@ -1,5 +1,4 @@
|
||||
#branch: lp:charm-helpers
|
||||
branch: /home/corey/src/charms/git/charm-helpers
|
||||
branch: lp:charm-helpers
|
||||
destination: tests/charmhelpers
|
||||
include:
|
||||
- contrib.amulet
|
||||
|
12
config.yaml
12
config.yaml
@ -3,20 +3,16 @@ options:
|
||||
default: None
|
||||
type: string
|
||||
description: |
|
||||
Specifies a YAML-formatted two-dimensional array listing the git
|
||||
repositories and branches from which to install OpenStack and its
|
||||
dependencies.
|
||||
Specifies a YAML-formatted dictionary listing the git
|
||||
repositories and branches from which to install OpenStack and
|
||||
its dependencies.
|
||||
|
||||
When openstack-origin-git is specified, openstack-specific
|
||||
packages will be installed from source rather than from the
|
||||
the nova-compute charm's openstack-origin repository.
|
||||
|
||||
Note that the installed config files will be determined based on
|
||||
the OpenStack release of the nova-compute charm's openstack-origin
|
||||
option.
|
||||
|
||||
Note also that this option is processed for the initial install
|
||||
only. Setting this option after deployment is not supported.
|
||||
the OpenStack release of the openstack-origin option.
|
||||
|
||||
For more details see README.md.
|
||||
rabbit-user:
|
||||
|
@ -2,6 +2,11 @@
|
||||
|
||||
import sys
|
||||
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
config_value_changed,
|
||||
git_install_requested,
|
||||
)
|
||||
|
||||
from charmhelpers.core.hookenv import (
|
||||
Hooks,
|
||||
UnregisteredHookError,
|
||||
@ -51,6 +56,10 @@ def install():
|
||||
def config_changed():
|
||||
CONFIGS.write_all()
|
||||
|
||||
if git_install_requested() and
|
||||
config_value_changed('openstack-origin-git'):
|
||||
git_install(config('openstack-origin-git'))
|
||||
|
||||
|
||||
@hooks.hook('amqp-relation-joined')
|
||||
def amqp_joined(relation_id=None):
|
||||
|
@ -6,6 +6,11 @@ from charmhelpers.contrib.openstack.neutron import neutron_plugin_attribute
|
||||
from copy import deepcopy
|
||||
|
||||
from charmhelpers.contrib.openstack import context, templating
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
git_install_requested,
|
||||
git_clone_and_install,
|
||||
git_src_dir,
|
||||
)
|
||||
from collections import OrderedDict
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
os_release,
|
||||
@ -87,12 +92,12 @@ def restart_map():
|
||||
return {k: v['services'] for k, v in resource_map().iteritems()}
|
||||
|
||||
|
||||
def git_install(projects):
|
||||
def git_install(projects_yaml):
|
||||
"""Perform setup, and install git repos specified in yaml parameter."""
|
||||
if git_install_requested():
|
||||
git_pre_install()
|
||||
git_clone_and_install(yaml.load(projects), core_project='neutron')
|
||||
git_post_install()
|
||||
git_clone_and_install(projects_yaml, core_project='neutron')
|
||||
git_post_install(projects_yaml)
|
||||
|
||||
|
||||
def git_pre_install():
|
||||
@ -121,9 +126,9 @@ def git_pre_install():
|
||||
write_file(l, '', owner='neutron', group='neutron', perms=0600)
|
||||
|
||||
|
||||
def git_post_install():
|
||||
def git_post_install(projects_yaml):
|
||||
"""Perform post-install setup."""
|
||||
src_etc = os.path.join(charm_dir(), '/mnt/openstack-git/neutron-api.git/etc')
|
||||
src_etc = os.path.join(git_src_dir(projects_yaml, 'neutron'), 'etc')
|
||||
configs = {
|
||||
'debug-filters': {
|
||||
'src': os.path.join(src_etc, 'neutron/rootwrap.d/debug.filters'),
|
||||
@ -175,10 +180,10 @@ def git_post_install():
|
||||
'log_file': '/var/log/neutron/ovs-cleanup.log',
|
||||
}
|
||||
|
||||
# NOTE(coreycb): Needs systemd support
|
||||
render('upstart/neutron-plugin-openvswitch-agent.upstart',
|
||||
'/etc/init/neutron-plugin-openvswitch-agent.conf',
|
||||
neutron_ovs_agent_context, perms=0o644)
|
||||
|
||||
render('upstart/neutron-ovs-cleanup.upstart',
|
||||
'/etc/init/neutron-ovs-cleanup.conf',
|
||||
neutron_ovs_cleanup_context, perms=0o644)
|
||||
|
9
tests/16-basic-trusty-icehouse-git
Executable file
9
tests/16-basic-trusty-icehouse-git
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""Amulet tests on a basic neutron-openvswitch git deployment on trusty-icehouse."""
|
||||
|
||||
from basic_deployment import NeutronOVSBasicDeployment
|
||||
|
||||
if __name__ == '__main__':
|
||||
deployment = NeutronOVSBasicDeployment(series='trusty', git=True)
|
||||
deployment.run_tests()
|
12
tests/18-basic-trusty-juno-git
Executable file
12
tests/18-basic-trusty-juno-git
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""Amulet tests on a basic neutron-openvswitch git deployment on trusty-juno."""
|
||||
|
||||
from basic_deployment import NeutronOVSBasicDeployment
|
||||
|
||||
if __name__ == '__main__':
|
||||
deployment = NeutronOVSBasicDeployment(series='trusty',
|
||||
openstack='cloud:trusty-juno',
|
||||
source='cloud:trusty-updates/juno',
|
||||
git=True)
|
||||
deployment.run_tests()
|
@ -2,6 +2,7 @@
|
||||
|
||||
import amulet
|
||||
import time
|
||||
import yaml
|
||||
|
||||
from charmhelpers.contrib.openstack.amulet.deployment import (
|
||||
OpenStackAmuletDeployment
|
||||
@ -24,10 +25,12 @@ u = OpenStackAmuletUtils(ERROR)
|
||||
class NeutronOVSBasicDeployment(OpenStackAmuletDeployment):
|
||||
"""Amulet tests on a basic neutron-openvswtich deployment."""
|
||||
|
||||
def __init__(self, series, openstack=None, source=None, stable=False):
|
||||
def __init__(self, series, openstack=None, source=None, git=False,
|
||||
stable=False):
|
||||
"""Deploy the entire test environment."""
|
||||
super(NeutronOVSBasicDeployment, self).__init__(series, openstack,
|
||||
source, stable)
|
||||
self.git = git
|
||||
self._add_services()
|
||||
self._add_relations()
|
||||
self._configure_services()
|
||||
@ -61,10 +64,21 @@ class NeutronOVSBasicDeployment(OpenStackAmuletDeployment):
|
||||
|
||||
def _configure_services(self):
|
||||
"""Configure all of the services."""
|
||||
neutron_ovs_config = {'openstack-origin-git':
|
||||
"{'neutron':"
|
||||
" {'repository': 'git://git.openstack.org/openstack/neutron.git',"
|
||||
" 'branch': 'stable/icehouse'}}"}
|
||||
neutron_ovs_config = {}
|
||||
if self.git:
|
||||
branch = 'stable/' + self._get_openstack_release_string()
|
||||
openstack_origin_git = {
|
||||
'repositories': [
|
||||
{'name': 'requirements',
|
||||
'repository': 'git://git.openstack.org/openstack/requirements',
|
||||
'branch': branch},
|
||||
{'name': 'neutron',
|
||||
'repository': 'git://git.openstack.org/openstack/neutron',
|
||||
'branch': branch},
|
||||
],
|
||||
'directory': '/mnt/openstack-git',
|
||||
}
|
||||
neutron_api_config['openstack-origin-git'] = yaml.dump(openstack_origin_git)
|
||||
configs = {'neutron-openvswitch': neutron_ovs_config}
|
||||
super(NeutronOVSBasicDeployment, self)._configure_services(configs)
|
||||
|
||||
|
@ -1,2 +1,4 @@
|
||||
import sys
|
||||
|
||||
sys.path.append('actions/')
|
||||
sys.path.append('hooks/')
|
||||
|
85
unit_tests/test_actions_git_reinstall.py
Normal file
85
unit_tests/test_actions_git_reinstall.py
Normal file
@ -0,0 +1,85 @@
|
||||
from mock import patch
|
||||
|
||||
with patch('charmhelpers.core.hookenv.config') as config:
|
||||
config.return_value = 'neutron'
|
||||
import neutron_ovs_utils as utils # noqa
|
||||
|
||||
import git_reinstall
|
||||
|
||||
from test_utils import (
|
||||
CharmTestCase
|
||||
)
|
||||
|
||||
TO_PATCH = [
|
||||
'config',
|
||||
]
|
||||
|
||||
|
||||
openstack_origin_git = \
|
||||
"""repositories:
|
||||
- {name: requirements,
|
||||
repository: 'git://git.openstack.org/openstack/requirements',
|
||||
branch: stable/juno}
|
||||
- {name: neutron,
|
||||
repository: 'git://git.openstack.org/openstack/neutron',
|
||||
branch: stable/juno}"""
|
||||
|
||||
|
||||
class TestNeutronOVSActions(CharmTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNeutronOVSActions, self).setUp(git_reinstall, TO_PATCH)
|
||||
self.config.side_effect = self.test_config.get
|
||||
|
||||
@patch.object(git_reinstall, 'action_set')
|
||||
@patch.object(git_reinstall, 'action_fail')
|
||||
@patch.object(git_reinstall, 'git_install')
|
||||
def test_git_reinstall(self, git_install, action_fail, action_set):
|
||||
self.test_config.set('openstack-origin-git', openstack_origin_git)
|
||||
|
||||
git_reinstall.git_reinstall()
|
||||
|
||||
git_install.assert_called_with(openstack_origin_git)
|
||||
self.assertTrue(git_install.called)
|
||||
self.assertFalse(action_set.called)
|
||||
self.assertFalse(action_fail.called)
|
||||
|
||||
@patch.object(git_reinstall, 'action_set')
|
||||
@patch.object(git_reinstall, 'action_fail')
|
||||
@patch.object(git_reinstall, 'git_install')
|
||||
@patch('charmhelpers.contrib.openstack.utils.config')
|
||||
def test_git_reinstall_not_configured(self, _config, git_install,
|
||||
action_fail, action_set):
|
||||
_config.return_value = 'none'
|
||||
|
||||
git_reinstall.git_reinstall()
|
||||
|
||||
msg = 'openstack-origin-git is not configured'
|
||||
action_fail.assert_called_with(msg)
|
||||
self.assertFalse(git_install.called)
|
||||
self.assertFalse(action_set.called)
|
||||
|
||||
@patch.object(git_reinstall, 'action_set')
|
||||
@patch.object(git_reinstall, 'action_fail')
|
||||
@patch.object(git_reinstall, 'git_install')
|
||||
@patch('charmhelpers.contrib.openstack.utils.config')
|
||||
def test_git_reinstall_exception(self, _config, git_install,
|
||||
action_fail, action_set):
|
||||
_config.return_value = openstack_origin_git
|
||||
e = OSError('something bad happened')
|
||||
git_install.side_effect = e
|
||||
traceback = (
|
||||
"Traceback (most recent call last):\n"
|
||||
" File \"actions/git_reinstall.py\", line 33, in git_reinstall\n"
|
||||
" git_install(config(\'openstack-origin-git\'))\n"
|
||||
" File \"/usr/lib/python2.7/dist-packages/mock.py\", line 964, in __call__\n" # noqa
|
||||
" return _mock_self._mock_call(*args, **kwargs)\n"
|
||||
" File \"/usr/lib/python2.7/dist-packages/mock.py\", line 1019, in _mock_call\n" # noqa
|
||||
" raise effect\n"
|
||||
"OSError: something bad happened\n")
|
||||
|
||||
git_reinstall.git_reinstall()
|
||||
|
||||
msg = 'git-reinstall resulted in an unexpected error'
|
||||
action_fail.assert_called_with(msg)
|
||||
action_set.assert_called_with({'traceback': traceback})
|
Loading…
Reference in New Issue
Block a user