Functional tests for notification APIs

This patch adds functional tests to check the behaviour
of notification APIs for notification types:-

a) Process
b) VM

Change-Id: I06b17e388773db5fb9ade31d70ee4b2ad8aefabf
This commit is contained in:
jayashri bidwe 2019-02-26 10:31:24 +05:30 committed by tpatil
parent 7321ee32fd
commit 5a86d3090d
6 changed files with 313 additions and 49 deletions

View File

@ -29,12 +29,11 @@ from masakari.tests import base
#: will determine where the functional tests will be run and what resource
#: defaults will be used to run the functional tests.
TEST_CLOUD_NAME = os.getenv('OS_CLOUD', 'devstack-admin')
TEST_CLOUD_REGION = openstack.config.get_cloud_region(cloud=TEST_CLOUD_NAME)
class BaseFunctionalTest(base.TestCase):
def setUp(self):
def setUp(self, ha_api_version="1.0"):
super(BaseFunctionalTest, self).setUp()
_log_stream = sys.stdout
@ -52,7 +51,15 @@ class BaseFunctionalTest(base.TestCase):
logger.addHandler(handler)
logger.propagate = False
self.conn = connection.Connection(config=TEST_CLOUD_REGION)
config = openstack.config.get_cloud_region(cloud=TEST_CLOUD_NAME)
self.admin_conn = connection.Connection(region_name=config.region_name,
auth=config.auth,
ha_api_version=ha_api_version)
devstack_user = os.getenv('OS_CLOUD', 'devstack')
devstack_region = openstack.config.get_cloud_region(
cloud=devstack_user)
self.conn = connection.Connection(config=devstack_region)
self.hypervisors = self._hypervisors()

View File

@ -0,0 +1,86 @@
# Copyright (C) 2019 NTT DATA
# All Rights Reserved.
#
# 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 oslo_service import loopingcall
from masakari.objects import fields
from masakari.tests.functional import base
class NotificationTestBase(base.BaseFunctionalTest):
SERVICE_TYPE = "COMPUTE"
HOST_TYPE = "COMPUTE"
CONTROL_ATTRIBUTES = "SSH"
SERVER_WAIT_INTERVAL = 1
SERVER_WAIT_PERIOD = 300
def setUp(self, ha_api_version="1.0", recovery_method="auto"):
super(NotificationTestBase, self).setUp(ha_api_version=ha_api_version)
self.recovery_method = recovery_method
if not self.hypervisors:
self.skipTest("Skip Test as there are no hypervisors "
"configured in nova")
# Create segment
self.segment = self.admin_conn.ha.create_segment(
name=self.getUniqueString(), recovery_method=self.recovery_method,
service_type=self.SERVICE_TYPE)
# Create valid host
host_name = self.hypervisors[0]['hypervisor_hostname']
self.host = self.admin_conn.ha.create_host(
segment_id=self.segment.uuid, name=host_name,
type=self.HOST_TYPE,
control_attributes=self.CONTROL_ATTRIBUTES)
# Delete segment which delete all hosts associated with it
self.addCleanup(self.admin_conn.ha.delete_segment, self.segment.uuid)
def check_notification_status(self, notification, wait_interval,
wait_period):
def wait_for_notification_status_finished():
result = self.admin_conn.ha.get_notification(
notification.notification_uuid)
if result.status == fields.NotificationStatus.FINISHED:
raise loopingcall.LoopingCallDone()
timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(
wait_for_notification_status_finished)
try:
timer.start(interval=wait_interval, initial_delay=1,
timeout=wait_period).wait()
except loopingcall.LoopingCallTimeOut:
self.fail("Timed out: Notification is not processed and "
"it's not in the finished status")
def check_server_status(self, server, status):
def wait_for_server_status_change():
instance = self.admin_conn.compute.get_server(server.id)
if instance.status == status:
raise loopingcall.LoopingCallDone()
timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(
wait_for_server_status_change)
try:
timer.start(interval=self.SERVER_WAIT_INTERVAL,
timeout=self.SERVER_WAIT_PERIOD).wait()
except loopingcall.LoopingCallTimeOut:
self.fail("Timed out: Instance is not in the expected"
" status: %s" % status)

View File

@ -30,13 +30,13 @@ class TestHosts(base.BaseFunctionalTest):
"configured in nova")
# Create segment
self.segment = self.conn.ha.create_segment(
self.segment = self.admin_conn.ha.create_segment(
name=self.getUniqueString(),
recovery_method=fields.FailoverSegmentRecoveryMethod.AUTO,
service_type='COMPUTE')
# Delete segment which deletes host/s associated with it
self.addCleanup(self.conn.ha.delete_segment, self.segment.uuid)
self.addCleanup(self.admin_conn.ha.delete_segment, self.segment.uuid)
def test_create_get(self):
# This test is for testing hosts create/get
@ -48,11 +48,11 @@ class TestHosts(base.BaseFunctionalTest):
'reserved': False,
'control_attributes': 'SSH'}
host = self.conn.ha.create_host(self.segment.uuid, **host_data)
host = self.admin_conn.ha.create_host(self.segment.uuid, **host_data)
self.assertDictContainsSubset(host_data, host)
result = self.conn.ha.get_host(host.uuid, self.segment.uuid)
result = self.admin_conn.ha.get_host(host.uuid, self.segment.uuid)
self.assertEqual('COMPUTE', result.type)
self.assertEqual(False, result.on_maintenance)
@ -64,19 +64,20 @@ class TestHosts(base.BaseFunctionalTest):
expected_hosts = []
for host in self.hypervisors:
host_obj = self.conn.ha.create_host(segment_id=self.segment.uuid,
name=host.hypervisor_hostname,
type='COMPUTE',
on_maintenance=False,
reserved=False,
control_attributes='SSH')
host_obj = self.admin_conn.ha.create_host(
segment_id=self.segment.uuid,
name=host.hypervisor_hostname,
type='COMPUTE',
on_maintenance=False,
reserved=False,
control_attributes='SSH')
# Deleting 'segment_id' as in GET list call of host 'segment_id'
# is not there in response
del host_obj['segment_id']
expected_hosts.append(host_obj)
hosts = self.conn.ha.hosts(self.segment.uuid)
hosts = self.admin_conn.ha.hosts(self.segment.uuid)
self.assertItemsEqual(expected_hosts, hosts)
@ddt.data(
@ -106,8 +107,8 @@ class TestHosts(base.BaseFunctionalTest):
'reserved': True,
'control_attributes': 'TCP'}
self.conn.ha.create_host(self.segment.uuid, **host_data_1)
self.conn.ha.create_host(self.segment.uuid, **host_data_2)
self.admin_conn.ha.create_host(self.segment.uuid, **host_data_1)
self.admin_conn.ha.create_host(self.segment.uuid, **host_data_2)
expected_host_data = {'on_maintenance': on_maintenance,
'type': host_type,
@ -116,7 +117,7 @@ class TestHosts(base.BaseFunctionalTest):
}
# Returns list of hosts based on filters
for host in self.conn.ha.hosts(self.segment.uuid,
for host in self.admin_conn.ha.hosts(self.segment.uuid,
on_maintenance=on_maintenance,
type=host_type,
reserved=reserved):
@ -127,20 +128,20 @@ class TestHosts(base.BaseFunctionalTest):
# This test is for updating created host and deletion of same
host_name = self.hypervisors[0]['hypervisor_hostname']
host = self.conn.ha.create_host(segment_id=self.segment.uuid,
host = self.admin_conn.ha.create_host(segment_id=self.segment.uuid,
name=host_name,
on_maintenance='False',
reserved='False',
type='COMPUTE',
control_attributes='SSH')
self.conn.ha.update_host(host['uuid'],
self.admin_conn.ha.update_host(host['uuid'],
segment_id=self.segment.uuid,
on_maintenance='True',
control_attributes='TCP',
reserved='True')
result = self.conn.ha.get_host(host.uuid,
result = self.admin_conn.ha.get_host(host.uuid,
host.failover_segment_id)
# Confirm host update
self.assertEqual(True, result.on_maintenance)
@ -153,16 +154,16 @@ class TestHosts(base.BaseFunctionalTest):
self.skipTest("Skipped as there is only one hypervisor "
"configured in nova")
host = self.conn.ha.create_host(segment_id=self.segment.uuid,
host = self.admin_conn.ha.create_host(segment_id=self.segment.uuid,
name=self.hypervisors[0]['hypervisor_hostname'],
type='COMPUTE',
control_attributes='SSH')
# Update host name
updated_host = self.conn.ha.update_host(host['uuid'],
updated_host = self.admin_conn.ha.update_host(host['uuid'],
segment_id=self.segment.uuid,
name=self.hypervisors[1]['hypervisor_hostname'])
result = self.conn.ha.get_host(host.uuid,
result = self.admin_conn.ha.get_host(host.uuid,
host.failover_segment_id)
self.assertEqual(result.name, updated_host.name)

View File

@ -0,0 +1,94 @@
# Copyright (C) 2019 NTT DATA
# All Rights Reserved.
#
# 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 oslo_utils import timeutils
from masakari.objects import fields
from masakari.tests.functional import notification_base as base
class NotificationProcessTestCase(base.NotificationTestBase):
NOTIFICATION_TYPE = "PROCESS"
NOTIFICATION_WAIT_INTERVAL = 1
NOTIFICATION_WAIT_PERIOD = 120
def setUp(self, ha_api_version="1.0"):
super(NotificationProcessTestCase, self).setUp(ha_api_version)
def _test_create_notification_event_stopped(self):
# Test to create notification for process with 'STOPPED' event type
notification = self.admin_conn.ha.create_notification(
type=self.NOTIFICATION_TYPE, hostname=self.host.name,
generated_time=timeutils.utcnow().replace(microsecond=0),
payload={"process_name": "nova-compute",
"event": fields.EventType.STOPPED})
self.check_notification_status(notification,
self.NOTIFICATION_WAIT_INTERVAL,
self.NOTIFICATION_WAIT_PERIOD)
notification = self.admin_conn.ha.get_notification(
notification.notification_uuid)
self.assertEqual(fields.NotificationStatus.FINISHED,
notification.status)
host = self.admin_conn.ha.get_host(self.host.uuid,
self.segment.uuid)
self.assertEqual(True, host.on_maintenance)
services = self.admin_conn.compute.services()
for service in services:
if service.binary == 'nova-compute':
if service.host == self.host.name:
# Enable n-cpu service which is disabled during
# DisableComputeNodetask of process recovery notification
# created above.
self.admin_conn.compute.enable_service(service,
service.host,
service.binary)
return notification
def _test_create_notification_event_start(self):
# Test to create notification for process with 'STARTED' event type
notification = self.admin_conn.ha.create_notification(
type=self.NOTIFICATION_TYPE, hostname=self.host.name,
generated_time=timeutils.utcnow().replace(microsecond=0),
payload={"process_name": "nova-compute",
"event": fields.EventType.STARTED})
self.check_notification_status(notification,
self.NOTIFICATION_WAIT_INTERVAL,
self.NOTIFICATION_WAIT_PERIOD)
notification = self.admin_conn.ha.get_notification(
notification.notification_uuid)
self.assertEqual(fields.NotificationStatus.FINISHED,
notification.status)
return notification
def test_create_notification_event_stopped(self):
# Test to create notification for process with 'STOPPED' event type
self._test_create_notification_event_stopped()
def test_create_notification_event_start(self):
# Test to create notification for process with 'STARTED' event type
self._test_create_notification_event_start()

View File

@ -25,19 +25,19 @@ class TestSegments(base.BaseFunctionalTest):
segment_data = {'name': self.getUniqueString(),
'recovery_method': fields.FailoverSegmentRecoveryMethod.AUTO,
'service_type': 'COMPUTE'}
segment = self.conn.ha.create_segment(**segment_data)
segment = self.admin_conn.ha.create_segment(**segment_data)
self.assertDictContainsSubset(segment_data, segment)
result = self.conn.ha.get_segment(segment.uuid)
result = self.admin_conn.ha.get_segment(segment.uuid)
self.assertEqual(segment.name, result.name)
self.assertEqual(segment.recovery_method, result.recovery_method)
self.assertEqual(segment.service_type, result.service_type)
self.conn.ha.delete_segment(segment.uuid)
self.admin_conn.ha.delete_segment(segment.uuid)
self.assertRaises(exceptions.ResourceNotFound,
self.conn.ha.get_segment, segment.uuid)
self.admin_conn.ha.get_segment, segment.uuid)
def test_create_delete_with_host(self):
# This test is for deleting a segment with hosts
@ -45,7 +45,7 @@ class TestSegments(base.BaseFunctionalTest):
self.skipTest("Skipped as there are no hypervisors "
"configured in nova")
segment = self.conn.ha.create_segment(
segment = self.admin_conn.ha.create_segment(
name=self.getUniqueString(),
recovery_method=fields.FailoverSegmentRecoveryMethod.AUTO,
service_type='COMPUTE')
@ -53,20 +53,20 @@ class TestSegments(base.BaseFunctionalTest):
# Create valid host
host_name = self.hypervisors[0]['hypervisor_hostname']
host = self.conn.ha.create_host(segment_id=segment.uuid,
host = self.admin_conn.ha.create_host(segment_id=segment.uuid,
name=host_name,
type='COMPUTE',
control_attributes='SSH')
result = self.conn.ha.get_segment(segment.uuid)
result = self.admin_conn.ha.get_segment(segment.uuid)
self.assertEqual(segment.name, result.name)
# Delete segment, which should delete hosts as well
self.conn.ha.delete_segment(segment['uuid'])
self.admin_conn.ha.delete_segment(segment['uuid'])
self.assertRaises(exceptions.ResourceNotFound,
self.conn.ha.get_segment, segment.uuid)
self.admin_conn.ha.get_segment, segment.uuid)
self.assertRaises(exceptions.ResourceNotFound,
self.conn.ha.get_host, host.uuid, segment.uuid)
self.admin_conn.ha.get_host, host.uuid, segment.uuid)
def test_list(self):
# This test is for listing segments using filters
@ -80,14 +80,14 @@ class TestSegments(base.BaseFunctionalTest):
'service_type': 'COMPUTE'}
# Create segments
segment_1 = self.conn.ha.create_segment(**segment_data_1)
segment_2 = self.conn.ha.create_segment(**segment_data_2)
segment_1 = self.admin_conn.ha.create_segment(**segment_data_1)
segment_2 = self.admin_conn.ha.create_segment(**segment_data_2)
# Delete segments
self.addCleanup(self.conn.ha.delete_segment, segment_1.uuid)
self.addCleanup(self.conn.ha.delete_segment, segment_2.uuid)
self.addCleanup(self.admin_conn.ha.delete_segment, segment_1.uuid)
self.addCleanup(self.admin_conn.ha.delete_segment, segment_2.uuid)
segments = self.conn.ha.segments()
segments = self.admin_conn.ha.segments()
self.assertItemsEqual([segment_1, segment_2], segments)
def test_list_with_filter(self):
@ -102,19 +102,19 @@ class TestSegments(base.BaseFunctionalTest):
'service_type': 'COMPUTE'}
# Create segments
segment_1 = self.conn.ha.create_segment(**segment_data_1)
segment_2 = self.conn.ha.create_segment(**segment_data_2)
segment_1 = self.admin_conn.ha.create_segment(**segment_data_1)
segment_2 = self.admin_conn.ha.create_segment(**segment_data_2)
# Delete segments
self.addCleanup(self.conn.ha.delete_segment, segment_1.uuid)
self.addCleanup(self.conn.ha.delete_segment, segment_2.uuid)
self.addCleanup(self.admin_conn.ha.delete_segment, segment_1.uuid)
self.addCleanup(self.admin_conn.ha.delete_segment, segment_2.uuid)
for seg_object in self.conn.ha.segments(
for seg_object in self.admin_conn.ha.segments(
recovery_method=fields.FailoverSegmentRecoveryMethod.AUTO):
self.assertDictContainsSubset(segment_data_1, seg_object)
for seg_object in self.conn.ha.segments(
for seg_object in self.admin_conn.ha.segments(
recovery_method=fields.FailoverSegmentRecoveryMethod.
RESERVED_HOST):
@ -126,27 +126,27 @@ class TestSegments(base.BaseFunctionalTest):
self.skipTest("Skipped as there are no hypervisors "
"configured in nova")
segment = self.conn.ha.create_segment(
segment = self.admin_conn.ha.create_segment(
name=self.getUniqueString(),
recovery_method=fields.FailoverSegmentRecoveryMethod.AUTO,
service_type='COMPUTE')
# Delete segment
self.addCleanup(self.conn.ha.delete_segment, segment.uuid)
self.addCleanup(self.admin_conn.ha.delete_segment, segment.uuid)
# Create valid host
host_name = self.hypervisors[0]['hypervisor_hostname']
self.conn.ha.create_host(segment_id=segment.uuid, name=host_name,
self.admin_conn.ha.create_host(segment_id=segment.uuid, name=host_name,
type='COMPUTE', control_attributes='SSH')
# Update segment
segment_1 = self.conn.ha.update_segment(segment.uuid,
segment_1 = self.admin_conn.ha.update_segment(segment.uuid,
name=self.getUniqueString(),
recovery_method=fields.FailoverSegmentRecoveryMethod.RESERVED_HOST,
service_type='CONTROLLER')
result = self.conn.ha.get_segment(segment.uuid)
result = self.admin_conn.ha.get_segment(segment.uuid)
self.assertEqual(segment_1.name, result.name)
self.assertEqual(segment_1.recovery_method, result.recovery_method)
self.assertEqual(segment_1.service_type, result.service_type)

View File

@ -0,0 +1,76 @@
# Copyright (C) 2019 NTT DATA
# All Rights Reserved.
#
# 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 oslo_utils import timeutils
from masakari.objects import fields
from masakari.tests.functional import notification_base as base
class NotificationVMTestCase(base.NotificationTestBase):
NOTIFICATION_TYPE = "VM"
NOTIFICATION_WAIT_INTERVAL = 1
NOTIFICATION_WAIT_PERIOD = 300
def setUp(self, ha_api_version="1.0"):
super(NotificationVMTestCase, self).setUp(ha_api_version)
def _test_create_notification(self):
# Get image and flavor to create server
image_uuids = [image.id for image in self.admin_conn.compute.images()]
flavors = [flavor.id for flavor in self.admin_conn.compute.flavors()]
# Create server
server = self.conn.compute.create_server(name='abc',
flavorRef=flavors[0],
imageRef=image_uuids[0],
metadata={
'HA_Enabled': 'True'})
self.addCleanup(self.conn.compute.delete_server, server)
self.check_server_status(server, 'ACTIVE')
self.admin_conn.compute.stop_server(server.id)
self.check_server_status(server, 'SHUTOFF')
notification = self.admin_conn.ha.create_notification(
type=self.NOTIFICATION_TYPE,
hostname=self.host.name,
generated_time=timeutils.utcnow().replace(microsecond=0),
payload={"instance_uuid": server.id,
"vir_domain_event": "STOPPED_FAILED",
"event": "LIFECYCLE"})
self.check_notification_status(notification,
self.NOTIFICATION_WAIT_INTERVAL,
self.NOTIFICATION_WAIT_PERIOD)
notification = self.admin_conn.instance_ha.get_notification(
notification.notification_uuid)
result = self.admin_conn.compute.get_server(server.id)
self.assertEqual(fields.NotificationStatus.FINISHED,
notification.status)
self.assertEqual('ACTIVE', result.status)
return notification
def test_create_notification(self):
# Test to create notification for VM notification type
self._test_create_notification()