os-faults/os_faults/tests/unit/api/test_human_api.py
Ilya Shakhat 9cf6337d5e Implement stress injection
Add new type of fault called "stress". When activated this fault
produces load on CPU, disk, memory or kernel of node. The functionality
is implemented with help of stress-ng utility.

Node collection API is extended:
   def stress(self, target, duration=None)

Human API is extended, examples of commands:
 * stress cpu for 20 seconds on controller.domain.tld node
 * stress disk for 10 seconds on all nodes
 * stress memory for 60 seconds on all nodes with keystone service

Change-Id: I8ddb2292b8dd19f476e4a5071259d1a90cbaa37c
Note: 'stress-ng' is required to be installed on target nodes.
2017-08-30 15:09:49 +02:00

234 lines
9.2 KiB
Python

# 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 ddt
import mock
from os_faults.api import error
from os_faults.api import human
from os_faults.api import node_collection
from os_faults.api import service as service_api
from os_faults.tests.unit import test
@ddt.ddt
class TestHumanAPI(test.TestCase):
def setUp(self):
super(TestHumanAPI, self).setUp()
self.destructor = mock.MagicMock()
self.service = mock.MagicMock(service_api.Service)
self.destructor.get_service = mock.MagicMock(return_value=self.service)
@ddt.data(('restart', 'keystone'), ('kill', 'nova-api'))
@ddt.unpack
def test_service_action(self, action, service_name):
command = '%s %s service' % (action, service_name)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
getattr(self.service, action).assert_called_once_with()
@ddt.data(('restart', 'keystone', 'random'), ('kill', 'nova-api', 'one'))
@ddt.unpack
def test_service_action_on_random_node(self, action, service_name, node):
nodes = mock.MagicMock(node_collection.NodeCollection)
self.service.get_nodes = mock.MagicMock(return_value=nodes)
one_node = mock.MagicMock(node_collection.NodeCollection)
nodes.pick = mock.MagicMock(return_value=one_node)
command = '%s %s service on %s node' % (action, service_name, node)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
getattr(self.service, action).assert_called_once_with(nodes=one_node)
nodes.pick.assert_called_once()
@ddt.data(('freeze', 'keystone', 5))
@ddt.unpack
def test_service_action_with_duration(self, action, service_name, t):
command = '%s %s service for %d seconds' % (action, service_name, t)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
getattr(self.service, action).assert_called_once_with(sec=t)
@ddt.data(('restart', 'keystone', 'node'), ('kill', 'nova-api', 'node'))
@ddt.unpack
def test_service_action_on_fqdn_node(self, action, service_name, node):
nodes = mock.MagicMock(node_collection.NodeCollection)
self.destructor.get_nodes.return_value = nodes
command = '%s %s service on %s node' % (action, service_name, node)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
self.destructor.get_nodes.assert_called_once_with(fqdns=[node])
getattr(self.service, action).assert_called_once_with(nodes=nodes)
@ddt.data(('reboot', 'keystone'), ('reset', 'nova-api'))
@ddt.unpack
def test_node_action_on_all_nodes(self, action, service_name):
nodes = mock.MagicMock(node_collection.NodeCollection)
self.service.get_nodes = mock.MagicMock(return_value=nodes)
command = '%s node with %s service' % (action, service_name)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
getattr(nodes, action).assert_called_once_with()
@ddt.data(('reboot', 'keystone'), ('reset', 'nova-api'))
@ddt.unpack
def test_node_action_on_random_node(self, action, service_name):
nodes = mock.MagicMock(node_collection.NodeCollection)
nodes2 = mock.MagicMock(node_collection.NodeCollection)
self.service.get_nodes = mock.MagicMock(return_value=nodes)
nodes.pick = mock.MagicMock(return_value=nodes2)
command = '%s one node with %s service' % (action, service_name)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
nodes.pick.assert_called_once()
getattr(nodes2, action).assert_called_once_with()
@ddt.data('reboot', 'poweroff', 'poweron')
def test_node_action_by_fqdn(self, action):
destructor = mock.MagicMock()
nodes = mock.MagicMock(node_collection.NodeCollection)
destructor.get_nodes = mock.MagicMock(return_value=nodes)
command = '%s node-2.local node' % action.capitalize()
human.execute(destructor, command)
destructor.get_nodes.assert_called_once_with(fqdns=['node-2.local'])
getattr(nodes, action).assert_called_once()
@ddt.data('cpu', 'memory', 'disk', 'kernel')
def test_stress_by_fqdn(self, target):
action = 'stress'
duration = 20
destructor = mock.MagicMock()
nodes = mock.MagicMock(node_collection.NodeCollection)
destructor.get_nodes = mock.MagicMock(return_value=nodes)
command = 'stress %s for %d seconds on node-2.local node' % (
target, duration)
human.execute(destructor, command)
destructor.get_nodes.assert_called_once_with(fqdns=['node-2.local'])
getattr(nodes, action).assert_called_once_with(
target=target, duration=duration)
@ddt.data('cpu', 'memory', 'disk', 'kernel')
def test_stress_target(self, target):
action = 'stress'
duration = 20
destructor = mock.MagicMock()
nodes = mock.MagicMock(node_collection.NodeCollection)
destructor.get_nodes = mock.MagicMock(return_value=nodes)
command = 'stress %s for %d seconds on nodes' % (target, duration)
human.execute(destructor, command)
destructor.get_nodes.assert_called_once_with()
getattr(nodes, action).assert_called_once_with(
target=target, duration=duration)
@ddt.data(('CPU', 'cpu', 10, 'keystone'),
('disk', 'disk', 20, 'nova-api'))
@ddt.unpack
def test_stress_by_service_on_fqdn_node(self, user_target, cmd_target,
duration, service_name):
action = 'stress'
nodes = mock.MagicMock(node_collection.NodeCollection)
self.service.get_nodes.return_value = nodes
command = 'stress %s for %d seconds on all nodes with %s service' % (
user_target, duration, service_name)
human.execute(self.destructor, command)
getattr(nodes, action).assert_called_once_with(
target=cmd_target, duration=duration)
@ddt.data(('Disconnect', 'disconnect'),
('Connect', 'connect'))
@ddt.unpack
def test_network_on_nodes_by_fqdn(self, user_action, action):
destructor = mock.MagicMock()
nodes = mock.MagicMock(node_collection.NodeCollection)
destructor.get_nodes = mock.MagicMock(return_value=nodes)
command = '%s storage network on node-2.local node' % user_action
human.execute(destructor, command)
destructor.get_nodes.assert_called_once_with(fqdns=['node-2.local'])
getattr(nodes, action).assert_called_once_with(network_name='storage')
@ddt.data(('disconnect', 'storage', 'mysql'),
('connect', 'management', 'rabbitmq'))
@ddt.unpack
def test_network_on_nodes_by_service(
self, action, network_name, service_name):
nodes = mock.MagicMock(node_collection.NodeCollection)
self.service.get_nodes = mock.MagicMock(return_value=nodes)
command = '%s %s network on node with %s service' % (
action, network_name, service_name)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
self.service.get_nodes.assert_called_once()
getattr(nodes, action).assert_called_once_with(
network_name=network_name)
@ddt.data(('disconnect', 'storage', 'one', 'mysql'),
('connect', 'management', 'random', 'rabbitmq'))
@ddt.unpack
def test_network_on_nodes_by_service_picked_node(
self, action, network_name, node, service_name):
nodes = mock.MagicMock(node_collection.NodeCollection)
nodes2 = mock.MagicMock(node_collection.NodeCollection)
self.service.get_nodes = mock.MagicMock(return_value=nodes)
nodes.pick = mock.MagicMock(return_value=nodes2)
command = '%s %s network on %s node with %s service' % (
action, network_name, node, service_name)
human.execute(self.destructor, command)
self.destructor.get_service.assert_called_once_with(name=service_name)
self.service.get_nodes.assert_called_once()
nodes.pick.assert_called_once()
getattr(nodes2, action).assert_called_once_with(
network_name=network_name)
def test_malformed_query(self):
destructor = mock.MagicMock()
command = 'inject some fault'
self.assertRaises(error.OSFException, human.execute, destructor,
command)