498 lines
14 KiB
Python
498 lines
14 KiB
Python
#
|
|
# Copyright(c) 2012-2020 Intel Corporation
|
|
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
#
|
|
|
|
import pytest
|
|
from unittest.mock import patch, mock_open
|
|
from textwrap import dedent
|
|
import helpers as h
|
|
|
|
import opencas
|
|
|
|
|
|
@patch("builtins.open", new_callable=mock_open)
|
|
def test_cas_config_from_file_exception(mock_file):
|
|
mock_file.raises = ValueError()
|
|
|
|
with pytest.raises(Exception):
|
|
opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
mock_file.assert_called_once_with("/dummy/file.conf", "r")
|
|
|
|
|
|
@patch(
|
|
"builtins.open",
|
|
new_callable=h.MockConfigFile,
|
|
buffer="""
|
|
[caches]
|
|
1 /dev/nvme0n1 WT
|
|
[cores]
|
|
1 1 /dev/sdc
|
|
""",
|
|
)
|
|
def test_cas_config_from_file_no_vertag(mock_file):
|
|
with pytest.raises(ValueError):
|
|
opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
|
|
@patch(
|
|
"builtins.open",
|
|
new_callable=h.MockConfigFile,
|
|
buffer="""
|
|
version=03.08.00
|
|
#[caches]
|
|
#1 /dev/nvme0n1 WT
|
|
#[cores]
|
|
#1 1 /dev/sdc
|
|
""",
|
|
)
|
|
@patch("opencas.cas_config.core_config.from_line")
|
|
@patch("opencas.cas_config.cache_config.from_line")
|
|
@patch("opencas.cas_config.insert_core")
|
|
@patch("opencas.cas_config.insert_cache")
|
|
def test_cas_config_from_file_comments_only(
|
|
mock_insert_cache,
|
|
mock_insert_core,
|
|
mock_cache_from_line,
|
|
mock_core_from_line,
|
|
mock_file,
|
|
):
|
|
|
|
config = opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
mock_cache_from_line.assert_not_called()
|
|
mock_core_from_line.assert_not_called()
|
|
mock_insert_cache.assert_not_called()
|
|
mock_insert_core.assert_not_called()
|
|
|
|
assert config.is_empty()
|
|
|
|
|
|
ConflictingConfigException = opencas.cas_config.ConflictingConfigException
|
|
AlreadyConfiguredException = opencas.cas_config.AlreadyConfiguredException
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"caches_config,cores_config,exception",
|
|
[
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT",
|
|
"2 /dev/dummy0n1 WT",
|
|
"3 /dev/dummy0n1 WT",
|
|
],
|
|
["1 1 /dev/dummyc"],
|
|
ConflictingConfigException,
|
|
),
|
|
(
|
|
["1 /dev/dummyc WT"],
|
|
["1 1 /dev/dummyc"],
|
|
ConflictingConfigException,
|
|
),
|
|
(
|
|
["1 /dev/dummya WT", "1 /dev/dummy0n1 WT"],
|
|
["1 1 /dev/dummyc"],
|
|
ConflictingConfigException,
|
|
),
|
|
(
|
|
["1 /dev/dummya WT", "1 /dev/dummya WT"],
|
|
["1 1 /dev/dummyc"],
|
|
AlreadyConfiguredException,
|
|
),
|
|
(
|
|
["1 /dev/dummya WT"],
|
|
["1 1 /dev/dummyc", "1 1 /dev/dummyc"],
|
|
AlreadyConfiguredException,
|
|
),
|
|
(
|
|
["2 /dev/dummya WT"],
|
|
["1 1 /dev/dummyc", "2 1 /dev/dummyb"],
|
|
KeyError,
|
|
),
|
|
(
|
|
["1 /dev/dummya WT", "2 /dev/dummy0n1 WT"],
|
|
["1 1 /dev/dummyc", "2 1 /dev/dummyc"],
|
|
ConflictingConfigException,
|
|
),
|
|
],
|
|
)
|
|
@patch("builtins.open", new_callable=h.MockConfigFile)
|
|
@patch("opencas.cas_config.cache_config.validate_config")
|
|
@patch("opencas.cas_config.core_config.validate_config")
|
|
def test_cas_config_from_file_inconsistent_configs(
|
|
mock_validate_core,
|
|
mock_validate_cache,
|
|
mock_file,
|
|
caches_config,
|
|
cores_config,
|
|
exception,
|
|
):
|
|
|
|
mock_file.set_contents(
|
|
dedent(
|
|
"""
|
|
version=3.8.0
|
|
[caches]
|
|
{0}
|
|
[cores]
|
|
{1}
|
|
"""
|
|
).format("\n".join(caches_config), "\n".join(cores_config))
|
|
)
|
|
|
|
with pytest.raises(exception):
|
|
opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
|
|
@patch(
|
|
"builtins.open",
|
|
new_callable=h.MockConfigFile,
|
|
buffer="""
|
|
version=3.8.0
|
|
[caches]
|
|
1 /dev/dummy0n1 WT
|
|
[cores]
|
|
1 1 /dev/dummyc
|
|
""",
|
|
)
|
|
@patch("opencas.cas_config.cache_config.validate_config")
|
|
@patch("opencas.cas_config.core_config.validate_config")
|
|
def test_cas_config_is_empty_non_empty(
|
|
mock_validate_core, mock_validate_cache, mock_file
|
|
):
|
|
|
|
config = opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
assert not config.is_empty()
|
|
|
|
|
|
def test_cas_config_double_add_cache():
|
|
config = opencas.cas_config()
|
|
|
|
cache = opencas.cas_config.cache_config(1, "/dev/dummy", "WT")
|
|
config.insert_cache(cache)
|
|
|
|
with pytest.raises(AlreadyConfiguredException):
|
|
config.insert_cache(cache)
|
|
|
|
|
|
def test_cas_config_double_add_core():
|
|
config = opencas.cas_config()
|
|
cache = opencas.cas_config.cache_config(1, "/dev/dummy1", "WT")
|
|
config.insert_cache(cache)
|
|
|
|
core = opencas.cas_config.core_config(1, 1, "/dev/dummy")
|
|
config.insert_core(core)
|
|
|
|
with pytest.raises(AlreadyConfiguredException):
|
|
config.insert_core(core)
|
|
|
|
|
|
def test_cas_config_insert_core_no_cache():
|
|
config = opencas.cas_config()
|
|
|
|
core = opencas.cas_config.core_config(1, 1, "/dev/dummy")
|
|
|
|
with pytest.raises(KeyError):
|
|
config.insert_core(core)
|
|
|
|
|
|
@patch("os.path.realpath")
|
|
def test_cas_config_add_same_cache_symlinked_01(mock_realpath):
|
|
mock_realpath.side_effect = (
|
|
lambda x: "/dev/dummy1" if x == "/dev/dummy_link" else x
|
|
)
|
|
|
|
config = opencas.cas_config()
|
|
cache = opencas.cas_config.cache_config(1, "/dev/dummy1", "WT")
|
|
config.insert_cache(cache)
|
|
|
|
cache_symlinked = opencas.cas_config.cache_config(
|
|
2, "/dev/dummy_link", "WB"
|
|
)
|
|
|
|
with pytest.raises(ConflictingConfigException):
|
|
config.insert_cache(cache_symlinked)
|
|
|
|
|
|
@patch("os.path.realpath")
|
|
def test_cas_config_add_same_cache_symlinked_02(mock_realpath):
|
|
mock_realpath.side_effect = (
|
|
lambda x: "/dev/dummy1" if x == "/dev/dummy_link" else x
|
|
)
|
|
|
|
config = opencas.cas_config()
|
|
cache = opencas.cas_config.cache_config(1, "/dev/dummy1", "WT")
|
|
config.insert_cache(cache)
|
|
|
|
cache_symlinked = opencas.cas_config.cache_config(
|
|
1, "/dev/dummy_link", "WB"
|
|
)
|
|
|
|
with pytest.raises(AlreadyConfiguredException):
|
|
config.insert_cache(cache_symlinked)
|
|
|
|
|
|
@patch("os.path.realpath")
|
|
def test_cas_config_add_same_core_symlinked_01(mock_realpath):
|
|
mock_realpath.side_effect = (
|
|
lambda x: "/dev/dummy1" if x == "/dev/dummy_link" else x
|
|
)
|
|
|
|
config = opencas.cas_config()
|
|
config.insert_cache(
|
|
opencas.cas_config.cache_config(1, "/dev/dummy_cache", "WB")
|
|
)
|
|
core = opencas.cas_config.core_config(1, 1, "/dev/dummy1")
|
|
config.insert_core(core)
|
|
|
|
core_symlinked = opencas.cas_config.core_config(1, 2, "/dev/dummy_link")
|
|
|
|
with pytest.raises(ConflictingConfigException):
|
|
config.insert_core(core_symlinked)
|
|
|
|
|
|
@patch("os.path.realpath")
|
|
def test_cas_config_add_same_core_symlinked_02(mock_realpath):
|
|
mock_realpath.side_effect = (
|
|
lambda x: "/dev/dummy1" if x == "/dev/dummy_link" else x
|
|
)
|
|
|
|
config = opencas.cas_config()
|
|
config.insert_cache(
|
|
opencas.cas_config.cache_config(1, "/dev/dummy_cache", "WB")
|
|
)
|
|
core = opencas.cas_config.core_config(1, 1, "/dev/dummy1")
|
|
config.insert_core(core)
|
|
|
|
core_symlinked = opencas.cas_config.core_config(1, 1, "/dev/dummy_link")
|
|
|
|
with pytest.raises(AlreadyConfiguredException):
|
|
config.insert_core(core_symlinked)
|
|
|
|
|
|
@patch("os.path.realpath")
|
|
@patch("os.listdir")
|
|
def test_cas_config_get_by_id_path(mock_listdir, mock_realpath):
|
|
mock_listdir.return_value = [
|
|
"wwn-1337deadbeef-x0x0",
|
|
"wwn-1337deadbeef-x0x0-part1",
|
|
"nvme-INTEL_SSDAAAABBBBBCCC_0984547ASDDJHHHFH",
|
|
]
|
|
mock_realpath.side_effect = (
|
|
lambda x: "/dev/dummy1"
|
|
if x == "/dev/disk/by-id/wwn-1337deadbeef-x0x0-part1"
|
|
else x
|
|
)
|
|
|
|
path = opencas.cas_config.get_by_id_path("/dev/dummy1")
|
|
|
|
assert path == "/dev/disk/by-id/wwn-1337deadbeef-x0x0-part1"
|
|
|
|
|
|
@patch("os.path.realpath")
|
|
@patch("os.listdir")
|
|
def test_cas_config_get_by_id_path_not_found(mock_listdir, mock_realpath):
|
|
mock_listdir.return_value = [
|
|
"wwn-1337deadbeef-x0x0",
|
|
"wwn-1337deadbeef-x0x0-part1",
|
|
"nvme-INTEL_SSDAAAABBBBBCCC_0984547ASDDJHHHFH",
|
|
]
|
|
mock_realpath.side_effect = lambda x: x
|
|
|
|
with pytest.raises(ValueError):
|
|
path = opencas.cas_config.get_by_id_path("/dev/dummy1")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"caches_config,cores_config",
|
|
[
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT",
|
|
"2 /dev/dummy0n2 WT",
|
|
"3 /dev/dummy0n3 WT",
|
|
],
|
|
["1 1 /dev/dummyc"],
|
|
),
|
|
([], []),
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT",
|
|
"2 /dev/dummy0n2 WT",
|
|
"3 /dev/dummy0n3 WT",
|
|
],
|
|
[
|
|
"1 1 /dev/dummyc1",
|
|
"2 200 /dev/dummyc2",
|
|
"3 100 /dev/dummyc3",
|
|
],
|
|
),
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT cleaning_policy=acp",
|
|
"2 /dev/dummy0n2 pt ioclass_file=mango.csv",
|
|
"3 /dev/dummy0n3 WA cache_line_size=16",
|
|
("4 /dev/dummyc wb cache_line_size=16,"
|
|
"ioclass_file=mango.csv,cleaning_policy=nop"),
|
|
],
|
|
[],
|
|
),
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT cleaning_policy=acp",
|
|
],
|
|
[
|
|
"1 1 /dev/dummy1 lazy_startup=true"
|
|
],
|
|
),
|
|
],
|
|
)
|
|
@patch("builtins.open", new_callable=h.MockConfigFile)
|
|
@patch("opencas.cas_config.cache_config.validate_config")
|
|
@patch("opencas.cas_config.core_config.validate_config")
|
|
def test_cas_config_from_file_to_file(
|
|
mock_validate_core,
|
|
mock_validate_cache,
|
|
mock_file,
|
|
caches_config,
|
|
cores_config,
|
|
):
|
|
"""
|
|
1. Read config from mocked file with parametrized caches and cores section
|
|
2. Serialize config back to mocked file
|
|
3. Check if serialized file is proper config file and the same content-wise
|
|
as the initial file. Specifically check:
|
|
* Version tag is present in first line
|
|
* There is only one of each [caches] and [cores] sections marking
|
|
* [cores] section comes after [caches]
|
|
* sets of caches and cores are equal before and after test
|
|
"""
|
|
|
|
mock_file.set_contents(
|
|
dedent(
|
|
"""
|
|
version=3.8.0
|
|
[caches]
|
|
{0}
|
|
[cores]
|
|
{1}
|
|
"""
|
|
).format("\n".join(caches_config), "\n".join(cores_config))
|
|
)
|
|
|
|
config = opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
config.write("/dummy/file.conf")
|
|
|
|
f = mock_file("/dummy/file.conf", "r")
|
|
contents_hashed = h.get_hashed_config_list(f)
|
|
|
|
assert contents_hashed[0] == "version=3.8.0"
|
|
assert contents_hashed.count("[caches]") == 1
|
|
assert contents_hashed.count("[cores]") == 1
|
|
|
|
caches_index = contents_hashed.index("[caches]")
|
|
cores_index = contents_hashed.index("[cores]")
|
|
|
|
assert cores_index > caches_index
|
|
|
|
caches_hashed = h.get_hashed_config_list(caches_config)
|
|
cores_hashed = h.get_hashed_config_list(cores_config)
|
|
|
|
assert set(caches_hashed) == set(
|
|
contents_hashed[caches_index + 1 : cores_index]
|
|
)
|
|
assert set(cores_hashed) == set(contents_hashed[cores_index + 1 :])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"caches_config,cores_config",
|
|
[
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT",
|
|
"2 /dev/dummy0n2 WT",
|
|
"3 /dev/dummy0n3 WT",
|
|
],
|
|
["1 1 /dev/dummyc"],
|
|
),
|
|
([], []),
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT",
|
|
"2 /dev/dummy0n2 WT",
|
|
"3 /dev/dummy0n3 WT",
|
|
],
|
|
[
|
|
"1 1 /dev/dummyc1",
|
|
"2 200 /dev/dummyc2",
|
|
"3 100 /dev/dummyc3",
|
|
],
|
|
),
|
|
(
|
|
[
|
|
"1 /dev/dummy0n1 WT cleaning_policy=acp",
|
|
"2 /dev/dummy0n2 pt ioclass_file=mango.csv",
|
|
"3 /dev/dummy0n3 WA cache_line_size=16",
|
|
("4 /dev/dummyc wb cache_line_size=16,"
|
|
"ioclass_file=mango.csv,cleaning_policy=nop"),
|
|
],
|
|
[],
|
|
),
|
|
],
|
|
)
|
|
@patch("builtins.open", new_callable=h.MockConfigFile)
|
|
@patch("opencas.cas_config.cache_config.validate_config")
|
|
@patch("opencas.cas_config.core_config.validate_config")
|
|
def test_cas_config_from_file_insert_cache_insert_core_to_file(
|
|
mock_validate_core,
|
|
mock_validate_cache,
|
|
mock_file,
|
|
caches_config,
|
|
cores_config,
|
|
):
|
|
"""
|
|
1. Read config from mocked file with parametrized caches and cores section
|
|
2. Add one core and one cache to config
|
|
3. Serialize config back to mocked file
|
|
4. Compare that config file after serialization is same content-wise with
|
|
initial + added core and cache
|
|
"""
|
|
|
|
mock_file.set_contents(
|
|
dedent(
|
|
"""
|
|
version=3.8.0
|
|
[caches]
|
|
{0}
|
|
[cores]
|
|
{1}
|
|
"""
|
|
).format("\n".join(caches_config), "\n".join(cores_config))
|
|
)
|
|
|
|
config = opencas.cas_config.from_file("/dummy/file.conf")
|
|
|
|
config.insert_cache(opencas.cas_config.cache_config(5, "/dev/mango", "WT"))
|
|
config.insert_core(opencas.cas_config.core_config(5, 1, "/dev/mango_core"))
|
|
|
|
config.write("/dummy/file.conf")
|
|
|
|
f = mock_file("/dummy/file.conf", "r")
|
|
contents_hashed = h.get_hashed_config_list(f)
|
|
|
|
caches_index = contents_hashed.index("[caches]")
|
|
cores_index = contents_hashed.index("[cores]")
|
|
|
|
caches_hashed = h.get_hashed_config_list(caches_config)
|
|
cores_hashed = h.get_hashed_config_list(cores_config)
|
|
|
|
assert set(contents_hashed[caches_index + 1 : cores_index]) - set(
|
|
caches_hashed
|
|
) == set(["5/dev/mangowt"])
|
|
assert set(contents_hashed[cores_index + 1 :]) - set(cores_hashed) == set(
|
|
["51/dev/mango_core"]
|
|
)
|