Add aggregates tests

* DB unit tests
* objects unit tests
* functional tests
* tempest

Change-Id: Ifb44bad51c0541105dcec091ee734d0cbba804ca
This commit is contained in:
Zhenguo Niu 2017-07-28 11:35:04 +08:00
parent 7baf214cd2
commit b17fbb9a28
6 changed files with 379 additions and 0 deletions

View File

@ -0,0 +1,87 @@
# Copyright 2017 Huawei Technologies Co., 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.
import mock
import six
from mogan.tests.functional.api import v1 as v1_test
class TestAggregate(v1_test.APITestV1):
AGGREGATE_UUIDS = ['ff28b5a2-73e5-431c-b4b7-1b96b74bca7b',
'94baf80e-2bae-4c3e-8dab-38b5441e7097',
'4bcfff85-c55a-493b-b544-b6c90b8fb397',
'e50fb289-4ee1-47dd-b371-6ca39af12888']
def setUp(self):
super(TestAggregate, self).setUp()
self.headers = self.gen_headers(self.context, roles="admin")
@mock.patch('oslo_utils.uuidutils.generate_uuid')
def _prepare_aggregates(self, mocked):
mocked.side_effect = self.AGGREGATE_UUIDS
for i in six.moves.xrange(4):
body = {"name": "test" + str(i),
"metadata": {"k1": "v1"}}
self.post_json('/aggregates', body,
headers=self.headers, status=201)
def test_aggregate_post(self):
body = {"name": "test",
"metadata": {"k1": "v1"}}
resp = self.post_json(
'/aggregates', body, headers=self.headers, status=201)
resp = resp.json
self.assertEqual('test', resp['name'])
self.assertEqual({'k1': 'v1'}, resp['metadata'])
self.assertIn('uuid', resp)
self.assertIn('links', resp)
def test_aggregate_get_all(self):
self._prepare_aggregates()
resp = self.get_json('/aggregates', headers=self.headers)
self.assertEqual(4, len(resp['aggregates']))
def test_aggregate_get_one(self):
self._prepare_aggregates()
resp = self.get_json('/aggregates/' + self.AGGREGATE_UUIDS[0],
headers=self.headers)
self.assertEqual('test0', resp['name'])
self.assertEqual({'k1': 'v1'}, resp['metadata'])
def test_aggregate_delete(self):
self._prepare_aggregates()
resp = self.get_json('/aggregates', headers=self.headers)
self.assertEqual(4, len(resp['aggregates']))
self.delete('/aggregates/' + self.AGGREGATE_UUIDS[0],
headers=self.headers, status=204)
resp = self.get_json('/aggregates', headers=self.headers)
self.assertEqual(3, len(resp['aggregates']))
def test_aggregate_update(self):
self._prepare_aggregates()
resp = self.get_json('/aggregates/' + self.AGGREGATE_UUIDS[0],
headers=self.headers)
self.assertEqual('test0', resp['name'])
self.patch_json('/aggregates/' + self.AGGREGATE_UUIDS[0],
[{'path': '/name', 'value': 'updated_name',
'op': 'replace'},
{'path': '/metadata/k2', 'value': 'v2',
'op': 'add'}],
headers=self.headers, status=200)
resp = self.get_json('/aggregates/' + self.AGGREGATE_UUIDS[0],
headers=self.headers)
self.assertEqual('updated_name', resp['name'])
self.assertItemsEqual({'k1': 'v1', 'k2': 'v2'}, resp['metadata'])

View File

@ -0,0 +1,78 @@
# Copyright 2017 Huawei Technologies Co., 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 tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from mogan.tests.tempest.api import base
class BaremetalComputeAPIAggregatesTest(base.BaseBaremetalComputeTest):
@classmethod
def resource_setup(cls):
super(BaremetalComputeAPIAggregatesTest, cls).resource_setup()
aggregate_body = {
"name": "tempest-test-aggregate",
"metadata": {"k1": "v1"}
}
cls.aggregate = cls.baremetal_compute_client.create_aggregate(
**aggregate_body)
@classmethod
def resource_cleanup(cls):
super(BaremetalComputeAPIAggregatesTest, cls).resource_cleanup()
cls.aggregate = cls.baremetal_compute_client.delete_aggregate(
cls.aggregate['uuid'])
@decorators.idempotent_id('82d94aab-62f1-4d85-bcb6-5c360f84d9b4')
def test_aggregate_create(self):
aggregate_body = {
"name": "test-aggregate",
"metadata": {"k1": "v1"}
}
aggregate = self.baremetal_compute_client.create_aggregate(
**aggregate_body)
self.assertEqual("test-aggregate", aggregate['name'])
self.assertItemsEqual({'k1': 'v1'}, aggregate['metadata'])
self.aggregate = self.baremetal_compute_client.delete_aggregate(
aggregate['uuid'])
@decorators.idempotent_id('c7062d65-09f7-4efa-8852-3ac543416c31')
def test_aggregate_show(self):
aggregate = self.baremetal_compute_client.show_aggregate(
self.aggregate['uuid'])
self.assertEqual("tempest-test-aggregate", aggregate['name'])
self.assertItemsEqual({'k1': 'v1'}, aggregate['metadata'])
@decorators.idempotent_id('a0520c12-4e7d-46ac-a0bc-c4c42fe3a344')
def test_aggregates_list(self):
aggregates = self.baremetal_compute_client.list_aggregates()
self.assertEqual(1, len(aggregates))
aggregate = aggregates[0]
self.assertEqual("tempest-test-aggregate", aggregate['name'])
self.assertItemsEqual({'k1': 'v1'}, aggregate['metadata'])
@decorators.idempotent_id('65614c7e-a1d9-4d1b-aa9a-6893616c0cc1')
def test_aggregate_delete(self):
aggregate_body = {
"name": "test-aggregate1",
"metadata": {"k1": "v1"}
}
aggregate = self.baremetal_compute_client.create_aggregate(
**aggregate_body)
self.aggregate = self.baremetal_compute_client.delete_aggregate(
aggregate['uuid'])
self.assertRaises(lib_exc.NotFound,
self.baremetal_compute_client.show_aggregate,
aggregate['uuid'])

View File

@ -234,6 +234,36 @@ class BaremetalComputeClient(rest_client.RestClient):
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
def list_aggregates(self):
uri = '%s/aggregates' % self.uri_prefix
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)['aggregates']
return rest_client.ResponseBodyList(resp, body)
def show_aggregate(self, aggregate_uuid):
uri = '%s/aggregates/%s' % (self.uri_prefix, aggregate_uuid)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
def delete_aggregate(self, aggregate_uuid):
uri = "%s/aggregates/%s" % (self.uri_prefix, aggregate_uuid)
resp, body = self.delete(uri)
self.expected_success(204, resp.status)
if body:
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
def create_aggregate(self, **kwargs):
uri = "%s/aggregates" % self.uri_prefix
body = self.serialize(kwargs)
resp, body = self.post(uri, body)
self.expected_success(201, resp.status)
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
class BaremetalNodeClient(rest_client.RestClient):
version = '1'
@ -297,6 +327,17 @@ class BaremetalNodeClient(rest_client.RestClient):
self.update_bm_node(node_id, updates)
class BaremetalAggregateClient(rest_client.RestClient):
version = '1'
uri_prefix = "v1"
def deserialize(self, body):
return json.loads(body.replace("\n", ""))
def serialize(self, body):
return json.dumps(body)
class Manager(manager.Manager):
load_clients = [

View File

@ -0,0 +1,75 @@
# Copyright 2017 Huawei Technologies Co.,LTD.
# 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.
"""Tests for manipulating Aggregates via the DB API"""
from oslo_utils import uuidutils
import six
from mogan.common import exception
from mogan.tests.unit.db import base
from mogan.tests.unit.db import utils
class DbAggregateTestCase(base.DbTestCase):
def setUp(self):
super(DbAggregateTestCase, self).setUp()
self.aggregate = utils.create_test_aggregate()
def test_create_aggregate(self):
utils.create_test_aggregate(name='testing')
def test_create_aggregate_already_exists(self):
self.assertRaises(exception.AggregateNameExists,
utils.create_test_aggregate,
name=self.aggregate['name'])
def test_get_aggregate_list(self):
uuids = [self.aggregate['uuid']]
for i in range(1, 6):
aggregate = utils.create_test_aggregate(
uuid=uuidutils.generate_uuid(),
name=six.text_type(i))
uuids.append(six.text_type(aggregate['uuid']))
res = self.dbapi.aggregate_get_all(self.context)
res_uuids = [r['uuid'] for r in res]
six.assertCountEqual(self, uuids, res_uuids)
def test_get_aggregate(self):
aggregate = self.dbapi.aggregate_get(
self.context, self.aggregate['uuid'])
self.assertEqual(self.aggregate['uuid'], aggregate['uuid'])
def test_get_aggregate_that_does_not_exist(self):
self.assertRaises(exception.AggregateNotFound,
self.dbapi.aggregate_get,
self.context,
uuidutils.generate_uuid())
def test_destroy_aggregate(self):
self.dbapi.aggregate_destroy(self.context, self.aggregate['id'])
self.assertRaises(exception.AggregateNotFound,
self.dbapi.aggregate_destroy,
self.context,
self.aggregate['id'])
def test_destroy_aggregate_that_does_not_exist(self):
self.assertRaises(exception.AggregateNotFound,
self.dbapi.aggregate_destroy,
self.context,
uuidutils.generate_uuid())

View File

@ -175,3 +175,32 @@ def create_test_quota(context={}, **kw):
dbapi = db_api.get_instance()
return dbapi.quota_create(context, quota)
def get_test_aggregate(**kw):
return {
'id': kw.get('id', 123),
'uuid': kw.get('uuid', uuidutils.generate_uuid()),
'name': kw.get('name', 'test'),
'updated_at': kw.get('updated_at'),
'created_at': kw.get('created_at'),
}
def create_test_aggregate(context={}, **kw):
"""Create test aggregate entry in DB and return the DB object.
Function to be used to create test Aggregate objects in the database.
:param context: The request context, for access checks.
:param kw: kwargs with overriding values for aggregate's attributes.
:returns: Test Aggregate DB object.
"""
agg = get_test_aggregate(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del agg['id']
dbapi = db_api.get_instance()
return dbapi.aggregate_create(context, agg)

View File

@ -0,0 +1,69 @@
#
# 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 mock
from oslo_context import context
from mogan import objects
from mogan.tests.unit.db import base
from mogan.tests.unit.db import utils
class TestAggregateObject(base.DbTestCase):
def setUp(self):
super(TestAggregateObject, self).setUp()
self.ctxt = context.get_admin_context()
self.fake_aggregate = utils.get_test_aggregate(context=self.ctxt)
self.fake_aggregate['metadetails'] = {}
def test_get(self):
uuid = self.fake_aggregate['uuid']
with mock.patch.object(self.dbapi, 'aggregate_get',
autospec=True) as mock_aggregate_get:
mock_aggregate_get.return_value = self.fake_aggregate
aggregate = objects.Aggregate.get(self.context, uuid)
mock_aggregate_get.assert_called_once_with(self.context, uuid)
self.assertEqual(self.context, aggregate._context)
def test_create(self):
with mock.patch.object(self.dbapi, 'aggregate_create',
autospec=True) as mock_aggregate_create:
mock_aggregate_create.return_value = self.fake_aggregate
aggregate = objects.Aggregate(self.context, **self.fake_aggregate)
values = aggregate.obj_get_changes()
aggregate.create(self.context)
mock_aggregate_create.assert_called_once_with(self.context, values)
self.assertEqual(self.fake_aggregate['uuid'], aggregate['uuid'])
def test_destroy(self):
agg_id = self.fake_aggregate['id']
with mock.patch.object(self.dbapi, 'aggregate_destroy',
autospec=True) as mock_aggregate_destroy:
mock_aggregate_destroy.return_value = self.fake_aggregate
aggregate = objects.Aggregate(self.context, **self.fake_aggregate)
aggregate.destroy(self.context)
mock_aggregate_destroy.assert_called_once_with(
self.context, agg_id)
def test_save(self):
id = self.fake_aggregate['id']
with mock.patch.object(self.dbapi, 'aggregate_update',
autospec=True) as mock_aggregate_update:
aggregate = objects.Aggregate(self.context, **self.fake_aggregate)
aggregate.name = 'changed_name'
updates = aggregate.obj_get_changes()
aggregate.save(self.context)
mock_aggregate_update.return_value = self.fake_aggregate
mock_aggregate_update.assert_called_once_with(
self.context, id, updates)