cinder/cinder/tests/unit/api/v3/test_backups.py

305 lines
13 KiB
Python

# Copyright (c) 2016 Intel, Inc.
# 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.
"""The backups V3 api."""
import copy
from unittest import mock
import ddt
from oslo_serialization import jsonutils
from oslo_utils import strutils
import webob
from cinder.api import microversions as mv
from cinder.api.openstack import api_version_request as api_version
from cinder.api.v3 import backups
from cinder.api.views import backups as backup_view
import cinder.backup
from cinder import context
from cinder import exception
from cinder.objects import fields
from cinder import test
from cinder.tests.unit.api import fakes
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import utils as test_utils
@ddt.ddt
class BackupsControllerAPITestCase(test.TestCase):
"""Test cases for backups API."""
def setUp(self):
super(BackupsControllerAPITestCase, self).setUp()
self.backup_api = cinder.backup.API()
self.ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID,
auth_token=True,
is_admin=True)
self.controller = backups.BackupsController()
self.user_context = context.RequestContext(
fake.USER_ID, fake.PROJECT_ID, auth_token=True)
def _fake_update_request(self, backup_id, version=mv.BACKUP_UPDATE):
req = fakes.HTTPRequest.blank('/v3/%s/backups/%s/update' %
(fake.PROJECT_ID, backup_id))
req.environ['cinder.context'].is_admin = True
req.headers['Content-Type'] = 'application/json'
req.headers['OpenStack-API-Version'] = 'volume ' + version
req.api_version_request = api_version.APIVersionRequest(version)
return req
def test_update_wrong_version(self):
req = self._fake_update_request(
fake.BACKUP_ID, version=mv.get_prior_version(mv.BACKUP_UPDATE))
body = {"backup": {"name": "Updated Test Name", }}
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.update, req, fake.BACKUP_ID,
body)
def test_backup_update_with_no_body(self):
# omit body from the request
req = self._fake_update_request(fake.BACKUP_ID)
self.assertRaises(exception.ValidationError,
self.controller.update,
req, fake.BACKUP_ID, body=None)
def test_backup_update_with_unsupported_field(self):
req = self._fake_update_request(fake.BACKUP_ID)
body = {"backup": {"id": fake.BACKUP2_ID,
"description": "", }}
self.assertRaises(exception.ValidationError,
self.controller.update,
req, fake.BACKUP_ID, body=body)
def test_backup_update_with_backup_not_found(self):
req = self._fake_update_request(fake.BACKUP_ID)
updates = {
"name": "Updated Test Name",
"description": "Updated Test description.",
}
body = {"backup": updates}
self.assertRaises(exception.NotFound,
self.controller.update,
req, fake.BACKUP_ID, body=body)
def _create_multiple_backups_with_different_project(self):
test_utils.create_backup(
context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True))
test_utils.create_backup(
context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True))
test_utils.create_backup(
context.RequestContext(fake.USER_ID, fake.PROJECT2_ID, True))
@ddt.data('backups', 'backups/detail')
def test_list_backup_with_count_param_version_not_matched(self, action):
self._create_multiple_backups_with_different_project()
is_detail = True if 'detail' in action else False
req = fakes.HTTPRequest.blank("/v3/%s?with_count=True" % action)
req.headers = mv.get_mv_header(
mv.get_prior_version(mv.SUPPORT_COUNT_INFO))
req.api_version_request = mv.get_api_version(
mv.get_prior_version(mv.SUPPORT_COUNT_INFO))
ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
req.environ['cinder.context'] = ctxt
res_dict = self.controller._get_backups(req, is_detail=is_detail)
self.assertNotIn('count', res_dict)
@ddt.data({'method': 'backups',
'display_param': 'True'},
{'method': 'backups',
'display_param': 'False'},
{'method': 'backups',
'display_param': '1'},
{'method': 'backups/detail',
'display_param': 'True'},
{'method': 'backups/detail',
'display_param': 'False'},
{'method': 'backups/detail',
'display_param': '1'}
)
@ddt.unpack
def test_list_backups_with_count_param(self, method, display_param):
self._create_multiple_backups_with_different_project()
is_detail = True if 'detail' in method else False
show_count = strutils.bool_from_string(display_param, strict=True)
# Request with 'with_count' and 'limit'
req = fakes.HTTPRequest.blank(
"/v3/%s?with_count=%s&limit=1" % (method, display_param))
req.headers = mv.get_mv_header(mv.SUPPORT_COUNT_INFO)
req.api_version_request = mv.get_api_version(mv.SUPPORT_COUNT_INFO)
ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, False)
req.environ['cinder.context'] = ctxt
res_dict = self.controller._get_backups(req, is_detail=is_detail)
self.assertEqual(1, len(res_dict['backups']))
if show_count:
self.assertEqual(2, res_dict['count'])
else:
self.assertNotIn('count', res_dict)
# Request with 'with_count'
req = fakes.HTTPRequest.blank(
"/v3/%s?with_count=%s" % (method, display_param))
req.headers = mv.get_mv_header(mv.SUPPORT_COUNT_INFO)
req.api_version_request = mv.get_api_version(mv.SUPPORT_COUNT_INFO)
ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, False)
req.environ['cinder.context'] = ctxt
res_dict = self.controller._get_backups(req, is_detail=is_detail)
self.assertEqual(2, len(res_dict['backups']))
if show_count:
self.assertEqual(2, res_dict['count'])
else:
self.assertNotIn('count', res_dict)
# Request with admin context and 'all_tenants'
req = fakes.HTTPRequest.blank(
"/v3/%s?with_count=%s&all_tenants=1" % (method, display_param))
req.headers = mv.get_mv_header(mv.SUPPORT_COUNT_INFO)
req.api_version_request = mv.get_api_version(mv.SUPPORT_COUNT_INFO)
ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True)
req.environ['cinder.context'] = ctxt
res_dict = self.controller._get_backups(req, is_detail=is_detail)
self.assertEqual(3, len(res_dict['backups']))
if show_count:
self.assertEqual(3, res_dict['count'])
else:
self.assertNotIn('count', res_dict)
@ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER),
mv.RESOURCE_FILTER,
mv.LIKE_FILTER)
@mock.patch('cinder.api.common.reject_invalid_filters')
def test_backup_list_with_general_filter(self, version, mock_update):
url = '/v3/%s/backups' % fake.PROJECT_ID
req = fakes.HTTPRequest.blank(url,
version=version,
use_admin_context=False)
self.controller.index(req)
if version != mv.get_prior_version(mv.RESOURCE_FILTER):
support_like = True if version == mv.LIKE_FILTER else False
mock_update.assert_called_once_with(req.environ['cinder.context'],
mock.ANY, 'backup',
support_like)
@ddt.data(mv.get_prior_version(mv.BACKUP_SORT_NAME),
mv.BACKUP_SORT_NAME)
def test_backup_list_with_name(self, version):
backup1 = test_utils.create_backup(
self.ctxt, display_name='b_test_name',
status=fields.BackupStatus.AVAILABLE)
backup2 = test_utils.create_backup(
self.ctxt, display_name='a_test_name',
status=fields.BackupStatus.AVAILABLE)
url = '/v3/%s/backups?sort_key=name' % fake.PROJECT_ID
req = fakes.HTTPRequest.blank(url, version=version)
if version == mv.get_prior_version(mv.BACKUP_SORT_NAME):
self.assertRaises(exception.InvalidInput,
self.controller.index,
req)
else:
expect = backup_view.ViewBuilder().summary_list(req,
[backup1, backup2])
result = self.controller.index(req)
self.assertEqual(expect, result)
def test_backup_update(self):
backup = test_utils.create_backup(
self.ctxt,
status=fields.BackupStatus.AVAILABLE)
req = self._fake_update_request(fake.BACKUP_ID)
new_name = "updated_test_name"
new_description = "Updated Test description."
updates = {
"name": new_name,
"description": new_description,
}
body = {"backup": updates}
self.controller.update(req,
backup.id,
body=body)
backup.refresh()
self.assertEqual(new_name, backup.display_name)
self.assertEqual(new_description,
backup.display_description)
@ddt.data({"backup": {"description": " sample description",
"name": " test name"}},
{"backup": {"description": "sample description ",
"name": "test "}},
{"backup": {"description": " sample description ",
"name": " test "}})
def test_backup_update_name_description_with_leading_trailing_spaces(
self, body):
backup = test_utils.create_backup(
self.ctxt,
status=fields.BackupStatus.AVAILABLE)
req = self._fake_update_request(fake.BACKUP_ID)
expected_body = copy.deepcopy(body)
self.controller.update(req,
backup.id,
body=body)
backup.refresh()
# backup update call doesn't return 'description' in response so get
# the updated backup to assert name and description
req = webob.Request.blank('/v2/%s/backups/%s' % (
fake.PROJECT_ID, backup.id))
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_context))
res_dict = jsonutils.loads(res.body)
self.assertEqual(expected_body['backup']['name'].strip(),
res_dict['backup']['name'])
self.assertEqual(expected_body['backup']['description'].strip(),
res_dict['backup']['description'])
@ddt.data(mv.get_prior_version(mv.BACKUP_METADATA),
mv.BACKUP_METADATA)
def test_backup_show_with_metadata(self, version):
backup = test_utils.create_backup(
self.ctxt, display_name='test_backup_metadata',
status=fields.BackupStatus.AVAILABLE)
# show backup metadata
url = '/v3/%s/backups/%s' % (fake.PROJECT_ID, backup.id)
req = fakes.HTTPRequest.blank(url, version=version)
backup_get = self.controller.show(req, backup.id)['backup']
if version == mv.get_prior_version(mv.BACKUP_METADATA):
self.assertNotIn('metadata', backup_get)
else:
self.assertIn('metadata', backup_get)
def test_backup_update_with_null_validate(self):
backup = test_utils.create_backup(
self.ctxt,
status=fields.BackupStatus.AVAILABLE)
req = self._fake_update_request(fake.BACKUP_ID)
updates = {
"name": None,
}
body = {"backup": updates}
self.controller.update(req,
backup.id,
body=body)
backup.refresh()
self.assertEqual(fields.BackupStatus.AVAILABLE, backup.status)