Skip to content

Commit

Permalink
test(py): add pytest-bdd feature tests for pools and replicas
Browse files Browse the repository at this point in the history
roughly translated from test/grpc/test_replica.js

resolves CAS-961
  • Loading branch information
cjones1024 committed Jul 19, 2021
1 parent 1a2ca89 commit 714b406
Show file tree
Hide file tree
Showing 4 changed files with 642 additions and 0 deletions.
35 changes: 35 additions & 0 deletions test/python/features/pool.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Feature: Mayastor pool management

Background:
Given a mayastor instance "ms0"

Scenario: creating a pool using disk with invalid block size
When the user attempts to create a pool specifying a disk with an invalid block size
Then the pool creation should fail

Scenario: creating a pool with multiple disks
When the user attempts to create a pool specifying multiple disks
Then the pool creation should fail

Scenario: creating a pool with an AIO disk
When the user creates a pool specifying a URI representing an aio disk
Then the pool should be created

Scenario: creating a pool with a name that already exists
Given a pool "p0"
When the user creates a pool with the name of an existing pool
Then the pool creation should succeed

Scenario: listing pools
Given a pool "p0"
When the user lists the current pools
Then the pool should appear in the output list

Scenario: destroying a pool
Given a pool "p0"
When the user destroys the pool
Then the pool should be destroyed

Scenario: destroying a pool that does not exist
When the user destroys a pool that does not exist
Then the pool destroy command should succeed
88 changes: 88 additions & 0 deletions test/python/features/replica.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
Feature: Mayastor replica management

Background:
Given a mayastor instance "ms0"
And a pool "p0"

Scenario: creating a replica
When the user creates an unshared replica
Then the replica is created
And the share state is unshared

Scenario: creating a replica shared over "iscsi"
When the user attempts to create a replica shared over "iscsi"
Then the create replica command should fail

Scenario: creating a replica with a name that already exists
Given a replica
When the user creates a replica that already exists
Then the create replica command should succeed

Scenario: listing replicas
Given a replica
When the user lists the current replicas
Then the replica should appear in the output list

Scenario: sharing a replica over "nvmf"
Given a replica that is unshared
When the user shares the replica over "nvmf"
Then the share state should change to "nvmf"

Scenario: sharing a replica over "iscsi"
Given a replica that is unshared
When the user attempts to share the replica over "iscsi"
Then the share replica command should fail

Scenario: sharing a replica that is already shared with the same protocol
Given a replica shared over "nvmf"
When the user shares the replica with the same protocol
Then the share replica command should succeed

Scenario: sharing a replica that is already shared with a different protocol
Given a replica shared over "nvmf"
When the user attempts to share the replica with a different protocol
Then the share replica command should fail

Scenario: unsharing a replica
Given a replica shared over "nvmf"
When the user unshares the replica
Then the share state should change to unshared

Scenario: destroying a replica
Given a replica
When the user destroys the replica
Then the replica should be destroyed

Scenario: destroying a replica that does not exist
When the user destroys a replica that does not exist
Then the replica destroy command should succeed

Scenario: listing replica stats
Given a replica
When the user gets replica stats
Then the stats for the replica should be listed

Scenario: creating a replica shared over "nvmf"
When the user creates a replica shared over "nvmf"
Then the replica is created
And the share state is "nvmf"

Scenario: listing replicas
Given a replica
When the user lists the current replicas
Then the replica should appear in the output list

Scenario: writing to a shared replica
Given a replica shared over "nvmf"
When the user writes to the replica
Then the write operation should succeed

Scenario: reading from a shared replica
Given a replica shared over "nvmf"
When the user reads from the replica
Then the read operation should succeed

Scenario: recreating a replica
Given a replica
When the user attempts to recreate the existing replica
Then the old data should have been reset
164 changes: 164 additions & 0 deletions test/python/test_bdd_pool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import pytest
from pytest_bdd import given, scenario, then, when, parsers

from common.command import run_cmd
from common.mayastor import mayastor_mod

import grpc
import mayastor_pb2 as pb


@scenario("features/pool.feature", "creating a pool using disk with invalid block size")
def test_fail_creating_a_pool_using_disk_with_invalid_block_size():
"Creating a pool using disk with invalid block size."


@scenario("features/pool.feature", "creating a pool with a name that already exists")
def test_creating_a_pool_with_a_name_that_already_exists():
"Creating a pool with a name that already exists."


@scenario("features/pool.feature", "creating a pool with an AIO disk")
def test_creating_a_pool_with_an_aio_disk():
"Creating a pool with an AIO disk."


@scenario("features/pool.feature", "creating a pool with multiple disks")
def test_fail_creating_a_pool_with_multiple_disks():
"Creating a pool with multiple disks."


@scenario("features/pool.feature", "destroying a pool")
def test_destroying_a_pool():
"Destroying a pool."


@scenario("features/pool.feature", "destroying a pool that does not exist")
def test_destroying_a_pool_that_does_not_exist():
"Destroying a pool that does not exist."


@scenario("features/pool.feature", "listing pools")
def test_listing_pools():
"Listing pools."


@pytest.fixture
def image_file():
name = "/tmp/ms0-disk0.img"
run_cmd(f"rm -f '{name}'", True)
run_cmd(f"truncate -s 64M '{name}'", True)
yield name
run_cmd(f"rm -f '{name}'", True)


@pytest.fixture
def find_pool(get_mayastor_instance):
def find(name):
for pool in get_mayastor_instance.ms.ListPools(pb.Null()).pools:
if pool.name == name:
return pool
return None

yield find


@pytest.fixture
def replica_pools(get_mayastor_instance):
pools = {}
yield pools
for name in pools.keys():
get_mayastor_instance.ms.DestroyPool(pb.DestroyPoolRequest(name=name))


@pytest.fixture
def create_pool(get_mayastor_instance, replica_pools):
def create(name, disks):
pool = get_mayastor_instance.ms.CreatePool(
pb.CreatePoolRequest(name=name, disks=disks)
)
replica_pools[name] = pool

yield create


@given(
parsers.parse('a mayastor instance "{name}"'),
target_fixture="get_mayastor_instance",
)
def get_mayastor_instance(mayastor_mod, name):
return mayastor_mod[name]


@given(parsers.parse('a pool "{name}"'), target_fixture="get_pool_name")
def get_pool_name(get_mayastor_instance, create_pool, name):
create_pool(name, ["malloc:///disk0?size_mb=100"])
return name


@when("the user creates a pool specifying a URI representing an aio disk")
def create_pool_from_aio_disk(get_mayastor_instance, create_pool, image_file):
create_pool("p0", [f"aio://{image_file}"])


@when("the user attempts to create a pool specifying a disk with an invalid block size")
def attempt_to_create_pool_from_disk_with_invalid_block_size(
get_mayastor_instance, create_pool
):
with pytest.raises(grpc.RpcError) as error:
create_pool("p0", "malloc:///disk0?size_mb=100&blk_size=1024")
assert error.value.code() == grpc.StatusCode.INVALID_ARGUMENT


@when("the user attempts to create a pool specifying multiple disks")
def attempt_to_create_pool_from_multiple_disks(get_mayastor_instance, create_pool):
with pytest.raises(grpc.RpcError) as error:
create_pool(
"p0", ["malloc:///disk0?size_mb=100", "malloc:///disk1?size_mb=100"]
)
assert error.value.code() == grpc.StatusCode.INVALID_ARGUMENT


@when("the user creates a pool with the name of an existing pool")
def create_pool_that_already_exists(get_mayastor_instance, create_pool, get_pool_name):
create_pool(get_pool_name, ["malloc:///disk0?size_mb=100"])


@when("the user destroys a pool that does not exist")
def destroy_pool_that_does_not_exist(get_mayastor_instance, find_pool):
assert find_pool("p0") == None
get_mayastor_instance.ms.DestroyPool(pb.DestroyPoolRequest(name="p0"))


@when("the user destroys the pool")
def destroy_pool(get_mayastor_instance, replica_pools, get_pool_name):
pool = replica_pools[get_pool_name]
get_mayastor_instance.ms.DestroyPool(pb.DestroyPoolRequest(name=pool.name))
del replica_pools[get_pool_name]


@when("the user lists the current pools", target_fixture="list_pools")
def list_pools(get_mayastor_instance):
return get_mayastor_instance.ms.ListPools(pb.Null(), wait_for_ready=True).pools


@then("the pool creation should fail")
def pool_creation_should_fail(find_pool):
assert find_pool("p0") == None


@then("the pool creation should succeed")
@then("the pool should be created")
def pool_creation_should_succeed(find_pool):
assert find_pool("p0") != None


@then("the pool destroy command should succeed")
@then("the pool should be destroyed")
def pool_destruction_should_succeed(find_pool):
assert find_pool("p0") == None


@then("the pool should appear in the output list")
def pool_should_appear_in_output(get_pool_name, list_pools):
assert get_pool_name in [pool.name for pool in list_pools]
Loading

0 comments on commit 714b406

Please sign in to comment.