Move service and cluster creation in test to utils

In this patch we move service and cluster creation methods from the
tests to the test utils file so they can be easily reused by other tests
that need to create them.

This change is required by the patch that fixes the replication freeze
mechanism but wasn't included in that patch to facilitate the review by
splitting the 2 different concepts: moving these convenience methods to
test utils and fixing the freeze mechanism.

Related-Bug: #1616974
Change-Id: I7d8552f38e9495f72a5c1af61f4f57b3b4683157
This commit is contained in:
Gorka Eguileor 2016-11-25 14:26:23 +01:00
parent 4d3e1e7c35
commit 73603d5248
4 changed files with 120 additions and 113 deletions

View File

@ -15,16 +15,14 @@
"""Tests for cluster table related operations."""
import datetime
import mock
from oslo_config import cfg
from oslo_utils import timeutils
from sqlalchemy.orm import exc
from cinder import db
from cinder import exception
from cinder.tests.unit import test_db_api
from cinder.tests.unit import utils
CONF = cfg.CONF
@ -33,43 +31,9 @@ CONF = cfg.CONF
class ClusterTestCase(test_db_api.BaseTest):
"""Unit tests for cinder.db.api.cluster_*."""
def _default_cluster_values(self):
return {
'name': 'cluster_name',
'binary': 'cinder-volume',
'disabled': False,
'disabled_reason': None,
'deleted': False,
'updated_at': None,
'deleted_at': None,
}
def _create_cluster(self, **values):
create_values = self._default_cluster_values()
create_values.update(values)
cluster = db.cluster_create(self.ctxt, create_values)
return db.cluster_get(self.ctxt, cluster.id, services_summary=True)
def _create_populated_cluster(self, num_services, num_down_svcs=0,
**values):
"""Helper method that creates a cluster with up and down services."""
up_time = timeutils.utcnow()
down_time = (up_time -
datetime.timedelta(seconds=CONF.service_down_time + 1))
cluster = self._create_cluster(**values)
svcs = [
db.service_create(
self.ctxt,
{'cluster_name': cluster.name,
'updated_at': down_time if i < num_down_svcs else up_time})
for i in range(num_services)
]
return cluster, svcs
def test_cluster_create_and_get(self):
"""Basic cluster creation test."""
values = self._default_cluster_values()
values = utils.default_cluster_values()
cluster = db.cluster_create(self.ctxt, values)
values['last_heartbeat'] = None
self.assertEqual(0, cluster.race_preventer)
@ -85,13 +49,13 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_create_cfg_disabled(self):
"""Test that create uses enable_new_services configuration option."""
self.override_config('enable_new_services', False)
cluster = self._create_cluster(disabled=None)
cluster = utils.create_cluster(self.ctxt, disabled=None)
self.assertTrue(cluster.disabled)
def test_cluster_create_disabled_preference(self):
"""Test that provided disabled value has highest priority on create."""
self.override_config('enable_new_services', False)
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
self.assertFalse(cluster.disabled)
def test_cluster_create_duplicate(self):
@ -104,9 +68,10 @@ class ClusterTestCase(test_db_api.BaseTest):
will not conflict with the creation of another cluster with the same
name.
"""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
self.assertRaises(exception.ClusterExists,
self._create_cluster,
utils.create_cluster,
self.ctxt,
name=cluster.name)
def test_cluster_create_not_duplicate(self):
@ -119,19 +84,20 @@ class ClusterTestCase(test_db_api.BaseTest):
will not conflict with the creation of another cluster with the same
name.
"""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
self.assertIsNone(db.cluster_destroy(self.ctxt, cluster.id))
self.assertIsNotNone(self._create_cluster(name=cluster.name))
self.assertIsNotNone(utils.create_cluster(self.ctxt,
name=cluster.name))
def test_cluster_get_fail(self):
"""Test that cluster get will fail if the cluster doesn't exists."""
self._create_cluster(name='cluster@backend')
utils.create_cluster(self.ctxt, name='cluster@backend')
self.assertRaises(exception.ClusterNotFound,
db.cluster_get, self.ctxt, 'name=cluster@backend2')
def test_cluster_get_by_name(self):
"""Getting a cluster by name will include backends if not specified."""
cluster = self._create_cluster(name='cluster@backend')
cluster = utils.create_cluster(self.ctxt, name='cluster@backend')
# Get without the backend
db_cluster = db.cluster_get(self.ctxt, name='cluster')
self.assertEqual(cluster.id, db_cluster.id)
@ -141,7 +107,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_without_summary(self):
"""Test getting cluster without summary information."""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
db_cluster = db.cluster_get(self.ctxt, cluster.id)
self.assertRaises(exc.DetachedInstanceError,
getattr, db_cluster, 'num_hosts')
@ -151,7 +117,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_with_summary_empty_cluster(self):
"""Test getting empty cluster with summary information."""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
db_cluster = db.cluster_get(self.ctxt, cluster.id,
services_summary=True)
self.assertEqual(0, db_cluster.num_hosts)
@ -160,7 +126,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_with_summary(self):
"""Test getting cluster with summary information."""
cluster, svcs = self._create_populated_cluster(3, 1)
cluster, svcs = utils.create_populated_cluster(self.ctxt, 3, 1)
db_cluster = db.cluster_get(self.ctxt, cluster.id,
services_summary=True)
self.assertEqual(3, db_cluster.num_hosts)
@ -169,7 +135,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_is_up_on_empty_cluster(self):
"""Test is_up filter works on empty clusters."""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
db_cluster = db.cluster_get(self.ctxt, cluster.id, is_up=False)
self.assertEqual(cluster.id, db_cluster.id)
self.assertRaises(exception.ClusterNotFound,
@ -177,7 +143,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_services_on_empty_cluster(self):
"""Test get_services filter works on empty clusters."""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
db_cluster = db.cluster_get(self.ctxt, cluster.id, get_services=True)
self.assertEqual(cluster.id, db_cluster.id)
self.assertListEqual([], db_cluster.services)
@ -185,9 +151,9 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_services(self):
"""Test services is properly populated on non empty cluster."""
# We create another cluster to see we do the selection correctly
self._create_populated_cluster(2, name='cluster2')
utils.create_populated_cluster(self.ctxt, 2, name='cluster2')
# We create our cluster with 2 up nodes and 1 down
cluster, svcs = self._create_populated_cluster(3, 1)
cluster, svcs = utils.create_populated_cluster(self.ctxt, 3, 1)
# Add a deleted service to the cluster
db.service_create(self.ctxt,
{'cluster_name': cluster.name,
@ -200,7 +166,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_is_up_all_are_down(self):
"""Test that is_up filter works when all services are down."""
cluster, svcs = self._create_populated_cluster(3, 3)
cluster, svcs = utils.create_populated_cluster(self.ctxt, 3, 3)
self.assertRaises(exception.ClusterNotFound,
db.cluster_get, self.ctxt, cluster.id, is_up=True)
db_cluster = db.cluster_get(self.ctxt, name=cluster.name, is_up=False)
@ -208,19 +174,19 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_by_num_down_hosts(self):
"""Test cluster_get by subquery field num_down_hosts."""
cluster, svcs = self._create_populated_cluster(3, 2)
cluster, svcs = utils.create_populated_cluster(self.ctxt, 3, 2)
result = db.cluster_get(self.ctxt, num_down_hosts=2)
self.assertEqual(cluster.id, result.id)
def test_cluster_get_by_num_hosts(self):
"""Test cluster_get by subquery field num_hosts."""
cluster, svcs = self._create_populated_cluster(3, 2)
cluster, svcs = utils.create_populated_cluster(self.ctxt, 3, 2)
result = db.cluster_get(self.ctxt, num_hosts=3)
self.assertEqual(cluster.id, result.id)
def test_cluster_destroy(self):
"""Test basic cluster destroy."""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
# On creation race_preventer is marked with a 0
self.assertEqual(0, cluster.race_preventer)
db.cluster_destroy(self.ctxt, cluster.id)
@ -237,7 +203,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_destroy_has_services(self):
"""Test that we cannot delete a cluster with non deleted services."""
cluster, svcs = self._create_populated_cluster(3, 1)
cluster, svcs = utils.create_populated_cluster(self.ctxt, 3, 1)
self.assertRaises(exception.ClusterHasHosts,
db.cluster_destroy, self.ctxt, cluster.id)
@ -248,7 +214,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_update(self):
"""Test basic cluster update."""
cluster = self._create_cluster()
cluster = utils.create_cluster(self.ctxt)
self.assertFalse(cluster.disabled)
db.cluster_update(self.ctxt, cluster.id, {'disabled': True})
db_cluster = db.cluster_get(self.ctxt, cluster.id)
@ -260,9 +226,11 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_all_matches(self):
"""Basic test of get_all with a matching filter."""
cluster1, svcs = self._create_populated_cluster(3, 1)
cluster2, svcs = self._create_populated_cluster(3, 2, name='cluster2')
cluster3, svcs = self._create_populated_cluster(3, 3, name='cluster3')
cluster1, svcs = utils.create_populated_cluster(self.ctxt, 3, 1)
cluster2, svcs = utils.create_populated_cluster(self.ctxt, 3, 2,
name='cluster2')
cluster3, svcs = utils.create_populated_cluster(self.ctxt, 3, 3,
name='cluster3')
expected = {cluster1.id, cluster2.id}
result = db.cluster_get_all(self.ctxt, is_up=True)
@ -271,7 +239,7 @@ class ClusterTestCase(test_db_api.BaseTest):
def test_cluster_get_all_no_match(self):
"""Basic test of get_all with a non matching filter."""
cluster1, svcs = self._create_populated_cluster(3, 3)
cluster1, svcs = utils.create_populated_cluster(self.ctxt, 3, 3)
result = db.cluster_get_all(self.ctxt, is_up=True)
self.assertListEqual([], result)

View File

@ -82,39 +82,19 @@ class DBAPIServiceTestCase(BaseTest):
"""Unit tests for cinder.db.api.service_*."""
def _get_base_values(self):
return {
'host': 'fake_host',
'cluster_name': None,
'binary': 'fake_binary',
'topic': 'fake_topic',
'report_count': 3,
'disabled': False
}
def _create_service(self, values):
v = self._get_base_values()
v.update(values)
service = db.service_create(self.ctxt, v)
# We need to read the contents from the DB if we have set updated_at
# or created_at fields
if 'updated_at' in values or 'created_at' in values:
service = db.service_get(self.ctxt, service.id)
return service
def test_service_create(self):
# Add a cluster value to the service
values = {'cluster_name': 'cluster'}
service = self._create_service(values)
service = utils.create_service(self.ctxt, values)
self.assertIsNotNone(service['id'])
expected = self._get_base_values()
expected = utils.default_service_values()
expected.update(values)
for key, value in expected.items():
self.assertEqual(value, service[key])
def test_service_destroy(self):
service1 = self._create_service({})
service2 = self._create_service({'host': 'fake_host2'})
service1 = utils.create_service(self.ctxt, {})
service2 = utils.create_service(self.ctxt, {'host': 'fake_host2'})
self.assertDictEqual(
{'deleted': True, 'deleted_at': mock.ANY},
@ -126,7 +106,7 @@ class DBAPIServiceTestCase(BaseTest):
db.service_get(self.ctxt, service2['id']))
def test_service_update(self):
service = self._create_service({})
service = utils.create_service(self.ctxt, {})
new_values = {
'host': 'fake_host1',
'binary': 'fake_binary1',
@ -144,12 +124,13 @@ class DBAPIServiceTestCase(BaseTest):
db.service_update, self.ctxt, 100500, {})
def test_service_get(self):
service1 = self._create_service({})
service1 = utils.create_service(self.ctxt, {})
real_service1 = db.service_get(self.ctxt, service1['id'])
self._assertEqualObjects(service1, real_service1)
def test_service_get_by_cluster(self):
service = self._create_service({'cluster_name': 'cluster@backend'})
service = utils.create_service(self.ctxt,
{'cluster_name': 'cluster@backend'})
# Search with an exact match
real_service = db.service_get(self.ctxt,
cluster_name='cluster@backend')
@ -163,7 +144,8 @@ class DBAPIServiceTestCase(BaseTest):
db.service_get, self.ctxt, 100500)
def test_service_get_by_host_and_topic(self):
service1 = self._create_service({'host': 'host1', 'topic': 'topic1'})
service1 = utils.create_service(self.ctxt,
{'host': 'host1', 'topic': 'topic1'})
real_service1 = db.service_get(self.ctxt, host='host1', topic='topic1')
self._assertEqualObjects(service1, real_service1)
@ -191,7 +173,7 @@ class DBAPIServiceTestCase(BaseTest):
db.cluster_create(self.ctxt, {'name': 'disabled_cluster',
'binary': 'b1',
'disabled': True}),
services = [self._create_service(vals) for vals in values]
services = [utils.create_service(self.ctxt, vals) for vals in values]
enabled = db.service_get_all(self.ctxt, disabled=False)
disabled = db.service_get_all(self.ctxt, disabled=True)
@ -222,7 +204,7 @@ class DBAPIServiceTestCase(BaseTest):
{'disabled': True, 'cluster_name': 'cluster_disabled'},
{'disabled': True, 'created_at': expired, 'updated_at': expired},
]
services = [self._create_service(vals) for vals in values]
services = [utils.create_service(self.ctxt, vals) for vals in values]
disabled_services = services[-3:]
non_disabled_services = services[:-3]
@ -251,7 +233,7 @@ class DBAPIServiceTestCase(BaseTest):
{'host': 'host4', 'disabled': True, 'topic': 't1'},
{'host': 'host3', 'topic': 't2'}
]
services = [self._create_service(vals) for vals in values]
services = [utils.create_service(self.ctxt, vals) for vals in values]
expected = services[:3]
real = db.service_get_all(self.ctxt, topic='t1')
self._assertEqualListsOfObjects(expected, real)
@ -263,7 +245,7 @@ class DBAPIServiceTestCase(BaseTest):
{'host': 'host4', 'disabled': True, 'binary': 'b1'},
{'host': 'host3', 'binary': 'b2'}
]
services = [self._create_service(vals) for vals in values]
services = [utils.create_service(self.ctxt, vals) for vals in values]
expected = services[:3]
real = db.service_get_all(self.ctxt, binary='b1')
self._assertEqualListsOfObjects(expected, real)
@ -273,7 +255,7 @@ class DBAPIServiceTestCase(BaseTest):
{'host': 'host1', 'binary': 'a'},
{'host': 'host2', 'binary': 'b'}
]
services = [self._create_service(vals) for vals in values]
services = [utils.create_service(self.ctxt, vals) for vals in values]
service1 = db.service_get(self.ctxt, host='host1', binary='a')
self._assertEqualObjects(services[0], service1)
@ -288,7 +270,7 @@ class DBAPIServiceTestCase(BaseTest):
{'host': 'host3', 'cluster_name': 'cluster@backend'},
{'host': 'host4', 'cluster_name': 'cluster2'},
]
services = [self._create_service(vals) for vals in values]
services = [utils.create_service(self.ctxt, vals) for vals in values]
expected = services[:3]
real = db.service_get_all(self.ctxt, cluster_name='cluster')
self._assertEqualListsOfObjects(expected, real)

View File

@ -18,6 +18,7 @@ import socket
import sys
import uuid
from oslo_config import cfg
from oslo_service import loopingcall
from oslo_utils import timeutils
import oslo_versionedobjects
@ -30,6 +31,9 @@ from cinder.objects import fields
from cinder.tests.unit import fake_constants as fake
CONF = cfg.CONF
def get_test_admin_context():
return context.get_admin_context()
@ -376,16 +380,6 @@ def create_qos(ctxt, testcase_instance=None, **kwargs):
return qos
def create_service(ctxt, binary='cinder-volume', host='host@backend',
topic='topic', disabled=False, availability_zone='cinder',
**kwargs):
kwargs.update(binary=binary, host=host, topic=topic, disabled=disabled,
availability_zone=availability_zone)
svc = objects.Service(ctxt, **kwargs)
svc.create()
return svc
class ZeroIntervalLoopingCall(loopingcall.FixedIntervalLoopingCall):
def start(self, interval, **kwargs):
kwargs['initial_delay'] = 0
@ -449,3 +443,63 @@ def generate_timeout_series(timeout):
while True:
iteration += 1
yield (iteration * timeout) + iteration
def default_service_values():
return {
'host': 'fake_host',
'cluster_name': None,
'binary': 'fake_binary',
'topic': 'fake_topic',
'report_count': 3,
'disabled': False,
}
def create_service(ctxt, values=None):
values = values or {}
v = default_service_values()
v.update(values)
service = db.service_create(ctxt, v)
# We need to read the contents from the DB if we have set updated_at
# or created_at fields
if 'updated_at' in values or 'created_at' in values:
service = db.service_get(ctxt, service.id)
return service
def default_cluster_values():
return {
'name': 'cluster_name',
'binary': 'cinder-volume',
'disabled': False,
'disabled_reason': None,
'deleted': False,
'updated_at': None,
'deleted_at': None,
}
def create_cluster(ctxt, **values):
create_values = default_cluster_values()
create_values.update(values)
cluster = db.cluster_create(ctxt, create_values)
return db.cluster_get(ctxt, cluster.id, services_summary=True)
def create_populated_cluster(ctxt, num_services, num_down_svcs=0, **values):
"""Helper method that creates a cluster with up and down services."""
up_time = timeutils.utcnow()
down_time = (up_time -
datetime.timedelta(seconds=CONF.service_down_time + 1))
cluster = create_cluster(ctxt, **values)
svcs = [
db.service_create(
ctxt,
{'cluster_name': cluster.name,
'host': 'host' + str(i),
'updated_at': down_time if i < num_down_svcs else up_time})
for i in range(num_services)
]
return cluster, svcs

View File

@ -16,6 +16,7 @@
import ddt
import mock
from cinder.common import constants
from cinder import exception
from cinder import objects
from cinder.objects import fields
@ -50,9 +51,10 @@ class ReplicationTestCase(base.BaseVolumeTestCase):
"""
svc = utils.create_service(
self.context,
host=self.host,
active_backend_id=svc_backend,
replication_status=fields.ReplicationStatus.FAILING_OVER)
{'host': self.host,
'binary': constants.VOLUME_BINARY,
'active_backend_id': svc_backend,
'replication_status': fields.ReplicationStatus.FAILING_OVER})
self.manager.failover_host(self.context, new_backend)
mock_getall.assert_called_once_with(self.context,
@ -69,9 +71,10 @@ class ReplicationTestCase(base.BaseVolumeTestCase):
def test_failover_host_driver_exception(self):
svc = utils.create_service(
self.context,
host=self.host,
active_backend_id=None,
replication_status=fields.ReplicationStatus.FAILING_OVER)
{'host': self.host,
'binary': constants.VOLUME_BINARY,
'active_backend_id': None,
'replication_status': fields.ReplicationStatus.FAILING_OVER})
self.manager.failover_host(self.context, mock.sentinel.backend_id)