[Manila] Add scenarios for Manila share metadata

List of changes:
- Added support for 'set' and 'delete' operations for share metadata.
- Added benchmark for setting and deleting share metadata.

Change-Id: I0ecb8c13218f23fd359045b05e0b596455b401b9
This commit is contained in:
Valeriy Ponomaryov 2016-11-04 20:47:57 +02:00
parent dd9c973b89
commit deb4d220a2
14 changed files with 779 additions and 3 deletions

View File

@ -58,3 +58,35 @@
failure_rate: failure_rate:
max: 0 max: 0
{% endfor %} {% endfor %}
ManilaShares.set_and_delete_metadata:
-
args:
sets: 1
set_size: 3
delete_size: 3
key_min_length: 1
key_max_length: 256
value_min_length: 1
value_max_length: 1024
runner:
type: "constant"
times: 10
concurrency: 10
context:
quotas:
manila:
shares: -1
gigabytes: -1
users:
tenants: 1
users_per_tenant: 1
manila_shares:
shares_per_tenant: 1
share_proto: "NFS"
size: 1
share_type: "dhss_false"
sla:
failure_rate:
max: 0

View File

@ -162,3 +162,37 @@
failure_rate: failure_rate:
max: 0 max: 0
{% endfor %} {% endfor %}
ManilaShares.set_and_delete_metadata:
-
args:
sets: 1
set_size: 3
delete_size: 3
key_min_length: 1
key_max_length: 256
value_min_length: 1
value_max_length: 1024
runner:
type: "constant"
times: 10
concurrency: 10
context:
quotas:
manila:
shares: -1
gigabytes: -1
share_networks: -1
users:
tenants: 1
users_per_tenant: 1
manila_share_networks:
use_share_networks: True
manila_shares:
shares_per_tenant: 1
share_proto: "NFS"
size: 1
share_type: "dhss_true"
sla:
failure_rate:
max: 0

View File

@ -13,5 +13,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
SHARES_CONTEXT_NAME = "manila_shares"
SHARE_NETWORKS_CONTEXT_NAME = "manila_share_networks" SHARE_NETWORKS_CONTEXT_NAME = "manila_share_networks"
SECURITY_SERVICES_CONTEXT_NAME = "manila_security_services" SECURITY_SERVICES_CONTEXT_NAME = "manila_security_services"

View File

@ -33,7 +33,7 @@ CONTEXT_NAME = consts.SHARE_NETWORKS_CONTEXT_NAME
@context.configure(name=CONTEXT_NAME, order=450) @context.configure(name=CONTEXT_NAME, order=450)
class ShareNetworks(context.Context): class ShareNetworks(context.Context):
"""This context creates resources specific for Manila project.""" """This context creates share networks for Manila project."""
CONFIG_SCHEMA = { CONFIG_SCHEMA = {
"type": "object", "type": "object",
"$schema": rally_consts.JSON_SCHEMA, "$schema": rally_consts.JSON_SCHEMA,

View File

@ -0,0 +1,107 @@
# Copyright 2016 Mirantis 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.
from oslo_config import cfg
from rally.common.i18n import _
from rally.common import logging
from rally.common import utils
from rally import consts as rally_consts
from rally.plugins.openstack.cleanup import manager as resource_manager
from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack.scenarios.manila import utils as manila_utils
from rally.task import context
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
CONTEXT_NAME = consts.SHARES_CONTEXT_NAME
@context.configure(name=CONTEXT_NAME, order=455)
class Shares(context.Context):
"""This context creates shares for Manila project."""
CONFIG_SCHEMA = {
"type": "object",
"$schema": rally_consts.JSON_SCHEMA,
"properties": {
"shares_per_tenant": {
"type": "integer",
"minimum": 1,
},
"size": {
"type": "integer",
"minimum": 1
},
"share_proto": {
"type": "string",
},
"share_type": {
"type": "string",
},
},
"additionalProperties": False
}
DEFAULT_CONFIG = {
"shares_per_tenant": 1,
"size": 1,
"share_proto": "NFS",
"share_type": None,
}
def _create_shares(self, manila_scenario, tenant_id, share_proto, size=1,
share_type=None):
tenant_ctxt = self.context["tenants"][tenant_id]
tenant_ctxt.setdefault("shares", [])
for i in range(self.config["shares_per_tenant"]):
kwargs = {"share_proto": share_proto, "size": size}
if share_type:
kwargs["share_type"] = share_type
share_networks = tenant_ctxt.get("manila_share_networks", {}).get(
"share_networks", [])
if share_networks:
kwargs["share_network"] = share_networks[
i % len(share_networks)]["id"]
share = manila_scenario._create_share(**kwargs)
tenant_ctxt["shares"].append(share.to_dict())
@logging.log_task_wrapper(
LOG.info, _("Enter context: `%s`") % CONTEXT_NAME)
def setup(self):
for user, tenant_id in (
utils.iterate_per_tenants(self.context.get("users", []))):
manila_scenario = manila_utils.ManilaScenario({
"task": self.task,
"user": user,
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
self._create_shares(
manila_scenario,
tenant_id,
self.config["share_proto"],
self.config["size"],
self.config["share_type"],
)
@logging.log_task_wrapper(LOG.info, _("Exit context: `%s`") % CONTEXT_NAME)
def cleanup(self):
resource_manager.cleanup(
names=["manila.shares"],
users=self.context.get("users", []),
)

View File

@ -15,6 +15,7 @@
from rally.common import logging from rally.common import logging
from rally import consts from rally import consts
from rally.plugins.openstack.context.manila import consts as manila_consts
from rally.plugins.openstack import scenario from rally.plugins.openstack import scenario
from rally.plugins.openstack.scenarios.manila import utils from rally.plugins.openstack.scenarios.manila import utils
from rally.task import validation from rally.task import validation
@ -228,3 +229,53 @@ class CreateAndListShare(utils.ManilaScenario):
self._create_share(share_proto=share_proto, size=size, **kwargs) self._create_share(share_proto=share_proto, size=size, **kwargs)
self.sleep_between(min_sleep, max_sleep) self.sleep_between(min_sleep, max_sleep)
self._list_shares(detailed=detailed) self._list_shares(detailed=detailed)
@validation.number("sets", minval=1, integer_only=True)
@validation.number("set_size", minval=1, integer_only=True)
@validation.number("key_min_length", minval=1, maxval=256, integer_only=True)
@validation.number("key_max_length", minval=1, maxval=256, integer_only=True)
@validation.number(
"value_min_length", minval=1, maxval=1024, integer_only=True)
@validation.number(
"value_max_length", minval=1, maxval=1024, integer_only=True)
@validation.required_services(consts.Service.MANILA)
@validation.required_openstack(users=True)
@validation.required_contexts(manila_consts.SHARES_CONTEXT_NAME)
@scenario.configure(
context={"cleanup": ["manila"]},
name="ManilaShares.set_and_delete_metadata")
class SetAndDeleteMetadata(utils.ManilaScenario):
def run(self, sets=10, set_size=3, delete_size=3,
key_min_length=1, key_max_length=256,
value_min_length=1, value_max_length=1024):
"""Sets and deletes share metadata.
This requires a share to be created with the shares
context. Additionally, ``sets * set_size`` must be greater
than or equal to ``deletes * delete_size``.
:param sets: how many set_metadata operations to perform
:param set_size: number of metadata keys to set in each
set_metadata operation
:param delete_size: number of metadata keys to delete in each
delete_metadata operation
:param key_min_length: minimal size of metadata key to set
:param key_max_length: maximum size of metadata key to set
:param value_min_length: minimal size of metadata value to set
:param value_max_length: maximum size of metadata value to set
"""
shares = self.context.get("tenant", {}).get("shares", [])
share = shares[self.context["iteration"] % len(shares)]
keys = self._set_metadata(
share=share,
sets=sets,
set_size=set_size,
key_min_length=key_min_length,
key_max_length=key_max_length,
value_min_length=value_min_length,
value_max_length=value_max_length)
self._delete_metadata(share=share, keys=keys, delete_size=delete_size)

View File

@ -13,9 +13,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import random
from oslo_config import cfg from oslo_config import cfg
from rally import exceptions
from rally.plugins.openstack.context.manila import consts from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack import scenario from rally.plugins.openstack import scenario
from rally.task import atomic from rally.task import atomic
@ -244,3 +246,65 @@ class ManilaScenario(scenario.OpenStackScenario):
"manila").share_networks.add_security_service( "manila").share_networks.add_security_service(
share_network, security_service) share_network, security_service)
return share_network return share_network
@atomic.action_timer("manila.set_metadata")
def _set_metadata(self, share, sets=1, set_size=1,
key_min_length=1, key_max_length=256,
value_min_length=1, value_max_length=1024):
"""Sets share metadata.
:param share: the share to set metadata on
:param sets: how many operations to perform
:param set_size: number of metadata keys to set in each operation
:param key_min_length: minimal size of metadata key to set
:param key_max_length: maximum size of metadata key to set
:param value_min_length: minimal size of metadata value to set
:param value_max_length: maximum size of metadata value to set
:returns: A list of keys that were set
:raises exceptions.InvalidArgumentsException: if invalid arguments
were provided.
"""
if not (key_min_length <= key_max_length and
value_min_length <= value_max_length):
raise exceptions.InvalidArgumentsException(
"Min length for keys and values of metadata can not be bigger "
"than maximum length.")
keys = []
for i in range(sets):
metadata = {}
for j in range(set_size):
if key_min_length == key_max_length:
key_length = key_min_length
else:
key_length = random.choice(
range(key_min_length, key_max_length))
if value_min_length == value_max_length:
value_length = value_min_length
else:
value_length = random.choice(
range(value_min_length, value_max_length))
key = self._generate_random_part(length=key_length)
keys.append(key)
metadata[key] = self._generate_random_part(length=value_length)
self.clients("manila").shares.set_metadata(share["id"], metadata)
return keys
@atomic.action_timer("manila.delete_metadata")
def _delete_metadata(self, share, keys, delete_size=3):
"""Deletes share metadata.
:param share: The share to delete metadata from.
:param delete_size: number of metadata keys to delete using one single
call.
:param keys: a list or tuple of keys to choose deletion candidates from
:raises exceptions.InvalidArgumentsException: if invalid arguments
were provided.
"""
if not (isinstance(keys, list) and keys):
raise exceptions.InvalidArgumentsException(
"Param 'keys' should be non-empty 'list'. keys = '%s'" % keys)
for i in range(0, len(keys), delete_size):
self.clients("manila").shares.delete_metadata(
share["id"], keys[i:i + delete_size])

View File

@ -0,0 +1,51 @@
{
"ManilaShares.set_and_delete_metadata": [
{
"args": {
"sets": 1,
"set_size": 3,
"delete_size": 3,
"key_min_length": 1,
"key_max_length": 256,
"value_min_length": 1,
"value_max_length": 1024
},
"runner": {
"type": "constant",
"times": 1,
"concurrency": 1
},
"context": {
"quotas": {
"manila": {
"shares": -1,
"gigabytes": -1,
"share_networks": -1
}
},
"users": {
"tenants": 1,
"users_per_tenant": 1,
"user_choice_method": "round_robin"
},
"network": {
"networks_per_tenant": 1,
"start_cidr": "99.0.0.0/24"
},
"manila_share_networks": {
"use_share_networks": true
},
"manila_shares": {
"shares_per_tenant": 1,
"share_proto": "NFS",
"size": 1
}
},
"sla": {
"failure_rate": {
"max": 0
}
}
}
]
}

View File

@ -0,0 +1,37 @@
---
ManilaShares.set_and_delete_metadata:
-
args:
sets: 1
set_size: 3
delete_size: 3
key_min_length: 1
key_max_length: 256
value_min_length: 1
value_max_length: 1024
runner:
type: "constant"
times: 1
concurrency: 1
context:
quotas:
manila:
shares: -1
gigabytes: -1
share_networks: -1
users:
tenants: 1
users_per_tenant: 1
user_choice_method: "round_robin"
network:
networks_per_tenant: 1
start_cidr: "99.0.0.0/24"
manila_share_networks:
use_share_networks: True
manila_shares:
shares_per_tenant: 1
share_proto: "NFS"
size: 1
sla:
failure_rate:
max: 0

View File

@ -0,0 +1,44 @@
{
"ManilaShares.set_and_delete_metadata": [
{
"args": {
"sets": 1,
"set_size": 3,
"delete_size": 3,
"key_min_length": 1,
"key_max_length": 256,
"value_min_length": 1,
"value_max_length": 1024
},
"runner": {
"type": "constant",
"times": 1,
"concurrency": 1
},
"context": {
"quotas": {
"manila": {
"shares": -1,
"gigabytes": -1,
"share_networks": -1
}
},
"users": {
"tenants": 1,
"users_per_tenant": 1,
"user_choice_method": "round_robin"
},
"manila_shares": {
"shares_per_tenant": 1,
"share_proto": "NFS",
"size": 1
}
},
"sla": {
"failure_rate": {
"max": 0
}
}
}
]
}

View File

@ -0,0 +1,32 @@
---
ManilaShares.set_and_delete_metadata:
-
args:
sets: 1
set_size: 3
delete_size: 3
key_min_length: 1
key_max_length: 256
value_min_length: 1
value_max_length: 1024
runner:
type: "constant"
times: 1
concurrency: 1
context:
quotas:
manila:
shares: -1
gigabytes: -1
share_networks: -1
users:
tenants: 1
users_per_tenant: 1
user_choice_method: "round_robin"
manila_shares:
shares_per_tenant: 1
share_proto: "NFS"
size: 1
sla:
failure_rate:
max: 0

View File

@ -0,0 +1,202 @@
# Copyright 2016 Mirantis 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.
import copy
import ddt
import mock
import six
from rally import consts as rally_consts
from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack.context.manila import manila_shares
from tests.unit import test
MANILA_UTILS_PATH = (
"rally.plugins.openstack.scenarios.manila.utils.ManilaScenario.")
class Fake(object):
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def __getitem__(self, item):
return getattr(self, item)
def to_dict(self):
return self.__dict__
@ddt.ddt
class SharesTestCase(test.TestCase):
TENANTS_AMOUNT = 3
USERS_PER_TENANT = 4
SHARES_PER_TENANT = 7
SHARE_NETWORKS = [{"id": "sn_%s_id" % d} for d in range(3)]
def _get_context(self, use_share_networks=False, shares_per_tenant=None,
share_size=1, share_proto="fake_proto", share_type=None):
tenants = {}
for t_id in range(self.TENANTS_AMOUNT):
tenants[six.text_type(t_id)] = {"name": six.text_type(t_id)}
users = []
for t_id in sorted(list(tenants.keys())):
for i in range(self.USERS_PER_TENANT):
users.append(
{"id": i, "tenant_id": t_id, "credential": "fake"})
context = {
"config": {
"users": {
"tenants": self.TENANTS_AMOUNT,
"users_per_tenant": self.USERS_PER_TENANT,
"user_choice_method": "round_robin",
},
consts.SHARE_NETWORKS_CONTEXT_NAME: {
"use_share_networks": use_share_networks,
"share_networks": self.SHARE_NETWORKS,
},
consts.SHARES_CONTEXT_NAME: {
"shares_per_tenant": (
shares_per_tenant or self.SHARES_PER_TENANT),
"size": share_size,
"share_proto": share_proto,
"share_type": share_type,
},
},
"admin": {
"credential": mock.MagicMock(),
},
"task": mock.MagicMock(),
"users": users,
"tenants": tenants,
}
if use_share_networks:
for t in context["tenants"].keys():
context["tenants"][t][consts.SHARE_NETWORKS_CONTEXT_NAME] = {
"share_networks": self.SHARE_NETWORKS,
}
return context
def test_init(self):
ctxt = {
"task": mock.MagicMock(),
"config": {
consts.SHARES_CONTEXT_NAME: {"foo": "bar"},
"fake": {"fake_key": "fake_value"},
},
}
inst = manila_shares.Shares(ctxt)
self.assertEqual(
{"foo": "bar", "shares_per_tenant": 1, "size": 1,
"share_proto": "NFS", "share_type": None},
inst.config)
self.assertIn(
rally_consts.JSON_SCHEMA, inst.CONFIG_SCHEMA.get("$schema"))
self.assertFalse(inst.CONFIG_SCHEMA.get("additionalProperties"))
self.assertEqual("object", inst.CONFIG_SCHEMA.get("type"))
props = inst.CONFIG_SCHEMA.get("properties", {})
self.assertEqual(
{"minimum": 1, "type": "integer"}, props.get("shares_per_tenant"))
self.assertEqual({"minimum": 1, "type": "integer"}, props.get("size"))
self.assertEqual({"type": "string"}, props.get("share_proto"))
self.assertEqual({"type": "string"}, props.get("share_type"))
self.assertEqual(455, inst.get_order())
self.assertEqual(consts.SHARES_CONTEXT_NAME, inst.get_name())
@mock.patch(MANILA_UTILS_PATH + "_create_share")
@ddt.data(True, False)
def test_setup(
self,
use_share_networks,
mock_manila_scenario__create_share):
share_type = "fake_share_type"
ctxt = self._get_context(
use_share_networks=use_share_networks, share_type=share_type)
inst = manila_shares.Shares(ctxt)
shares = [
Fake(id="fake_share_id_%d" % s_id)
for s_id in range(self.TENANTS_AMOUNT * self.SHARES_PER_TENANT)
]
mock_manila_scenario__create_share.side_effect = shares
expected_ctxt = copy.deepcopy(ctxt)
inst.setup()
self.assertEqual(
self.TENANTS_AMOUNT * self.SHARES_PER_TENANT,
mock_manila_scenario__create_share.call_count)
for d in range(self.TENANTS_AMOUNT):
self.assertEqual(
[
s.to_dict() for s in shares[
(d * self.SHARES_PER_TENANT):(
d * self.SHARES_PER_TENANT + self.SHARES_PER_TENANT
)
]
],
inst.context.get("tenants", {}).get("%s" % d, {}).get("shares")
)
self.assertEqual(expected_ctxt["task"], inst.context.get("task"))
self.assertEqual(expected_ctxt["config"], inst.context.get("config"))
self.assertEqual(expected_ctxt["users"], inst.context.get("users"))
if use_share_networks:
mock_calls = [
mock.call(
share_proto=ctxt["config"][consts.SHARES_CONTEXT_NAME][
"share_proto"],
size=ctxt["config"][consts.SHARES_CONTEXT_NAME]["size"],
share_type=ctxt["config"][consts.SHARES_CONTEXT_NAME][
"share_type"],
share_network=self.SHARE_NETWORKS[
int(t_id) % len(self.SHARE_NETWORKS)]["id"]
) for t_id in expected_ctxt["tenants"].keys()
]
else:
mock_calls = [
mock.call(
share_proto=ctxt["config"][consts.SHARES_CONTEXT_NAME][
"share_proto"],
size=ctxt["config"][consts.SHARES_CONTEXT_NAME]["size"],
share_type=ctxt["config"][consts.SHARES_CONTEXT_NAME][
"share_type"],
) for t_id in expected_ctxt["tenants"].keys()
]
mock_manila_scenario__create_share.assert_has_calls(
mock_calls, any_order=True)
@mock.patch(MANILA_UTILS_PATH + "_create_share")
@mock.patch("rally.plugins.openstack.cleanup.manager.cleanup")
def test_cleanup(
self,
mock_cleanup_manager_cleanup,
mock_manila_scenario__create_share):
ctxt = self._get_context()
inst = manila_shares.Shares(ctxt)
shares = [
Fake(id="fake_share_id_%d" % s_id)
for s_id in range(self.TENANTS_AMOUNT * self.SHARES_PER_TENANT)
]
mock_manila_scenario__create_share.side_effect = shares
inst.setup()
inst.cleanup()
mock_cleanup_manager_cleanup.assert_called_once_with(
names=["manila.shares"],
users=inst.context.get("users", []),
)

View File

@ -209,3 +209,37 @@ class ManilaSharesTestCase(test.ScenarioTestCase):
scenario._create_share.assert_called_once_with(**params) scenario._create_share.assert_called_once_with(**params)
scenario.sleep_between.assert_called_once_with(3, 4) scenario.sleep_between.assert_called_once_with(3, 4)
scenario._list_shares.assert_called_once_with(detailed=detailed) scenario._list_shares.assert_called_once_with(detailed=detailed)
@ddt.data(
({}, 0, 0),
({}, 1, 1),
({}, 2, 2),
({}, 3, 0),
({"sets": 5, "set_size": 8, "delete_size": 10}, 1, 1),
)
@ddt.unpack
def test_set_and_delete_metadata(self, params, iteration, share_number):
scenario = shares.SetAndDeleteMetadata()
share_list = [{"id": "fake_share_%s_id" % d} for d in range(3)]
scenario.context = {"tenant": {"shares": share_list}}
scenario.context["iteration"] = iteration
scenario._set_metadata = mock.MagicMock()
scenario._delete_metadata = mock.MagicMock()
expected_set_params = {
"share": share_list[share_number],
"sets": params.get("sets", 10),
"set_size": params.get("set_size", 3),
"key_min_length": params.get("key_min_length", 1),
"key_max_length": params.get("key_max_length", 256),
"value_min_length": params.get("value_min_length", 1),
"value_max_length": params.get("value_max_length", 1024),
}
scenario.run(**params)
scenario._set_metadata.assert_called_once_with(**expected_set_params)
scenario._delete_metadata.assert_called_once_with(
share=share_list[share_number],
keys=scenario._set_metadata.return_value,
delete_size=params.get("delete_size", 3),
)

View File

@ -16,6 +16,7 @@
import ddt import ddt
import mock import mock
from rally import exceptions
from rally.plugins.openstack.context.manila import consts from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack.scenarios.manila import utils from rally.plugins.openstack.scenarios.manila import utils
from tests.unit import test from tests.unit import test
@ -41,12 +42,14 @@ class ManilaScenarioTestCase(test.ScenarioTestCase):
}, },
"iteration": 0, "iteration": 0,
} }
self.scenario.generate_random_name = mock.Mock() fake_random_name = "fake_random_name_value"
self.scenario.generate_random_name = mock.Mock(
return_value=fake_random_name)
self.scenario._create_share("nfs") self.scenario._create_share("nfs")
self.clients("manila").shares.create.assert_called_once_with( self.clients("manila").shares.create.assert_called_once_with(
"nfs", 1, name=self.scenario.generate_random_name.return_value, "nfs", 1, name=fake_random_name,
share_network=self.scenario.context["tenant"][ share_network=self.scenario.context["tenant"][
consts.SHARE_NETWORKS_CONTEXT_NAME]["share_networks"][0]["id"]) consts.SHARE_NETWORKS_CONTEXT_NAME]["share_networks"][0]["id"])
@ -213,3 +216,87 @@ class ManilaScenarioTestCase(test.ScenarioTestCase):
self.clients( self.clients(
"manila").share_networks.add_security_service.assert_has_calls([ "manila").share_networks.add_security_service.assert_has_calls([
mock.call(fake_sn, fake_ss)]) mock.call(fake_sn, fake_ss)])
@ddt.data(
{"key_min_length": 5, "key_max_length": 4},
{"value_min_length": 5, "value_max_length": 4},
)
def test__set_metadata_wrong_params(self, params):
self.assertRaises(
exceptions.InvalidArgumentsException,
self.scenario._set_metadata,
{"id": "fake_share_id"}, **params)
@ddt.data(
{},
{"sets": 0, "set_size": 1},
{"sets": 1, "set_size": 1},
{"sets": 5, "set_size": 7},
{"sets": 5, "set_size": 2},
{"key_min_length": 1, "key_max_length": 1},
{"key_min_length": 1, "key_max_length": 2},
{"key_min_length": 256, "key_max_length": 256},
{"value_min_length": 1, "value_max_length": 1},
{"value_min_length": 1, "value_max_length": 2},
{"value_min_length": 1024, "value_max_length": 1024},
)
def test__set_metadata(self, params):
share = {"id": "fake_share_id"}
sets = params.get("sets", 1)
set_size = params.get("set_size", 1)
gen_name_calls = sets * set_size * 2
data = range(gen_name_calls)
generator_data = iter(data)
def fake_random_name(prefix="fake", length="fake"):
return next(generator_data)
scenario = self.scenario
scenario.clients = mock.MagicMock()
scenario._generate_random_part = mock.MagicMock(
side_effect=fake_random_name)
keys = scenario._set_metadata(share, **params)
self.assertEqual(
gen_name_calls,
scenario._generate_random_part.call_count)
self.assertEqual(
params.get("sets", 1),
scenario.clients.return_value.shares.set_metadata.call_count)
scenario.clients.return_value.shares.set_metadata.assert_has_calls([
mock.call(
share["id"],
dict([(j, j + 1) for j in data[
i * set_size * 2: (i + 1) * set_size * 2: 2]])
) for i in range(sets)
])
self.assertEqual([i for i in range(0, gen_name_calls, 2)], keys)
@ddt.data(None, [], {"fake_set"}, {"fake_key": "fake_value"})
def test__delete_metadata_wrong_params(self, keys):
self.assertRaises(
exceptions.InvalidArgumentsException,
self.scenario._delete_metadata,
"fake_share", keys=keys,
)
@ddt.data(
{"keys": [i for i in range(30)]},
{"keys": list(range(7)), "delete_size": 2},
{"keys": list(range(7)), "delete_size": 3},
{"keys": list(range(7)), "delete_size": 4},
)
def test__delete_metadata(self, params):
share = {"id": "fake_share_id"}
delete_size = params.get("delete_size", 3)
keys = params.get("keys", [])
scenario = self.scenario
scenario.clients = mock.MagicMock()
scenario._delete_metadata(share, **params)
scenario.clients.return_value.shares.delete_metadata.assert_has_calls([
mock.call(share["id"], keys[i:i + delete_size])
for i in range(0, len(keys), delete_size)
])