From df1ba933def9cbeeccf1415fd4e2c015bb72c9a0 Mon Sep 17 00:00:00 2001 From: Jan Musial Date: Thu, 24 Oct 2019 14:13:24 +0200 Subject: [PATCH] Update tests Signed-off-by: Jan Musial --- test/utils_tests/opencas-py-tests/helpers.py | 10 +- .../opencas-py-tests/test_cas_config_01.py | 8 + .../test_cas_config_core_01.py | 67 +- .../test_helper_functions_01.py | 583 ++++++++++++++++++ 4 files changed, 641 insertions(+), 27 deletions(-) create mode 100644 test/utils_tests/opencas-py-tests/test_helper_functions_01.py diff --git a/test/utils_tests/opencas-py-tests/helpers.py b/test/utils_tests/opencas-py-tests/helpers.py index 9f5ac23..a552931 100644 --- a/test/utils_tests/opencas-py-tests/helpers.py +++ b/test/utils_tests/opencas-py-tests/helpers.py @@ -52,7 +52,7 @@ def get_hashed_config_list(conf): def get_conf_line_hash(line): """ - Removes whitespace, lowercases, comments and sorts cache params if present. + Removes whitespace, lowercases, comments and sorts params if present. Returns empty line for comment-only lines We don't care about order of params and kinds of whitespace in config lines @@ -60,15 +60,15 @@ def get_conf_line_hash(line): testing we pretend we don't. """ - def sort_cache_params(params): + def sort_params(params): return ",".join(sorted(params.split(","))) line = line.split("#")[0] - cache_params_pattern = re.compile(r"(.*?\s)(\S+=\S+)") - match = cache_params_pattern.search(line) + params_pattern = re.compile(r"(.*?\s)(\S+=\S+)") + match = params_pattern.search(line) if match: - sorted_params = sort_cache_params(match.group(2)) + sorted_params = sort_params(match.group(2)) line = match.group(1) + sorted_params return "".join(line.lower().split()) diff --git a/test/utils_tests/opencas-py-tests/test_cas_config_01.py b/test/utils_tests/opencas-py-tests/test_cas_config_01.py index d7031ed..ea9e764 100644 --- a/test/utils_tests/opencas-py-tests/test_cas_config_01.py +++ b/test/utils_tests/opencas-py-tests/test_cas_config_01.py @@ -339,6 +339,14 @@ def test_cas_config_get_by_id_path_not_found(mock_listdir, mock_realpath): ], [], ), + ( + [ + "1 /dev/dummy0n1 WT cleaning_policy=acp", + ], + [ + "1 1 /dev/dummy1 lazy_startup=true" + ], + ), ], ) @patch("builtins.open", new_callable=h.MockConfigFile) diff --git a/test/utils_tests/opencas-py-tests/test_cas_config_core_01.py b/test/utils_tests/opencas-py-tests/test_cas_config_core_01.py index 9b93acc..f011bea 100644 --- a/test/utils_tests/opencas-py-tests/test_cas_config_core_01.py +++ b/test/utils_tests/opencas-py-tests/test_cas_config_core_01.py @@ -18,12 +18,15 @@ import opencas " ", "#", " # ", - ("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg" + ( + "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg" "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlI" - "GV0IGRvbG9yZSBtYWduYSBhbGlxdWEu"), + "GV0IGRvbG9yZSBtYWduYSBhbGlxdWEu" + ), " # ? } { ! ", - "1 1 /dev/sda /dev/sdb", - "1 2 1 /dev/sda ", + "1 1 /dev/not_a_real_device /dev/sdb", + "1 2 1 /dev/not_a_real_device ", + "1 2 1 /dev/not_a_real_device dinosaur=velociraptor", ], ) @mock.patch("opencas.cas_config.core_config.validate_config") @@ -32,17 +35,39 @@ def test_core_config_from_line_parsing_checks_01(mock_validate, line): opencas.cas_config.core_config.from_line(line) -@pytest.mark.parametrize("line", ["1 1 /dev/sda", "1 1 /dev/sda "]) -@mock.patch("opencas.cas_config.core_config.validate_config") -def test_core_config_from_line_parsing_checks_02(mock_validate, line): - opencas.cas_config.core_config.from_line(line) +@pytest.mark.parametrize( + "line", + [ + "1 1 /dev/not_a_real_device", + "1 1 /dev/not_a_real_device ", + "1 1 /dev/not_a_real_device lazy_startup=true", + "1 1 /dev/not_a_real_device lazy_startup=false", + "1 1 /dev/not_a_real_device lazy_startup=False", + "1 1 /dev/not_a_real_device lazy_startup=True", + ], +) +def test_core_config_from_line_parsing_checks_02(line): + opencas.cas_config.core_config.from_line(line, allow_incomplete=True) + + +@pytest.mark.parametrize( + "line", + [ + "1 1 /dev/not_a_real_device dinosaur=velociraptor", + "1 1 /dev/not_a_real_device lazy_startup=maybe", + "1 1 /dev/not_a_real_device lazy_saturday=definitely", + "1 1 /dev/not_a_real_device 00000=345", + "1 1 /dev/not_a_real_device eval(38+4)", + ], +) +def test_core_config_from_line_parsing_checks_params_01(line): + with pytest.raises(ValueError): + opencas.cas_config.core_config.from_line(line, allow_incomplete=True) @mock.patch("os.path.exists") @mock.patch("os.stat") -def test_core_config_from_line_device_is_directory( - mock_stat, mock_path_exists -): +def test_core_config_from_line_device_is_directory(mock_stat, mock_path_exists): mock_path_exists.side_effect = h.get_mock_os_exists(["/home/user/stuff"]) mock_stat.return_value = mock.Mock(st_mode=stat.S_IFDIR) @@ -57,7 +82,7 @@ def test_core_config_from_line_device_not_present(mock_stat, mock_path_exists): mock_stat.side_effect = ValueError() with pytest.raises(ValueError): - opencas.cas_config.core_config.from_line("1 1 /dev/sda") + opencas.cas_config.core_config.from_line("1 1 /dev/not_a_real_device") def test_core_config_from_line_recursive_multilevel(): @@ -72,7 +97,7 @@ def test_core_config_from_line_multilevel(): @mock.patch("opencas.cas_config.check_block_device") def test_core_config_from_line_allow_incomplete(mock_check_block,): opencas.cas_config.core_config.from_line( - "1 1 /dev/sda", allow_incomplete=True + "1 1 /dev/not_a_real_device", allow_incomplete=True ) assert not mock_check_block.called @@ -100,10 +125,10 @@ def test_core_config_from_line_allow_incomplete(mock_check_block,): def test_core_config_from_line_cache_id_validation_01( mock_stat, mock_path_exists, cache_id, core_id ): - mock_path_exists.side_effect = h.get_mock_os_exists(["/dev/sda"]) + mock_path_exists.side_effect = h.get_mock_os_exists(["/dev/not_a_real_device"]) mock_stat.return_value = mock.Mock(st_mode=stat.S_IFBLK) - line = "{0} {1} /dev/sda".format(cache_id, core_id) + line = "{0} {1} /dev/not_a_real_device".format(cache_id, core_id) with pytest.raises(ValueError): opencas.cas_config.core_config.from_line(line) @@ -117,10 +142,10 @@ def test_core_config_from_line_cache_id_validation_01( def test_core_config_from_line_cache_id_validation_02( mock_stat, mock_path_exists, cache_id, core_id ): - mock_path_exists.side_effect = h.get_mock_os_exists(["/dev/sda"]) + mock_path_exists.side_effect = h.get_mock_os_exists(["/dev/not_a_real_device"]) mock_stat.return_value = mock.Mock(st_mode=stat.S_IFBLK) - line = "{0} {1} /dev/sda".format(cache_id, core_id) + line = "{0} {1} /dev/not_a_real_device".format(cache_id, core_id) opencas.cas_config.core_config.from_line(line) @@ -128,8 +153,8 @@ def test_core_config_from_line_cache_id_validation_02( @pytest.mark.parametrize( "cache_id,core_id,device", [ - ("1", "1", "/dev/sda"), - ("16384", "4095", "/dev/sda1"), + ("1", "1", "/dev/not_a_real_device"), + ("16384", "4095", "/dev/not_a_real_device"), ("16384", "0", "/dev/nvme0n1p"), ("100", "5", "/dev/dm-10"), ], @@ -148,9 +173,7 @@ def test_core_config_from_line_cache_id_validation( core_reference.validate_config() - core_after = opencas.cas_config.core_config.from_line( - core_reference.to_line() - ) + core_after = opencas.cas_config.core_config.from_line(core_reference.to_line()) assert core_after.cache_id == core_reference.cache_id assert core_after.core_id == core_reference.core_id assert core_after.device == core_reference.device diff --git a/test/utils_tests/opencas-py-tests/test_helper_functions_01.py b/test/utils_tests/opencas-py-tests/test_helper_functions_01.py new file mode 100644 index 0000000..90983e2 --- /dev/null +++ b/test/utils_tests/opencas-py-tests/test_helper_functions_01.py @@ -0,0 +1,583 @@ +# +# Copyright(c) 2019 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause-Clear +# + +import pytest +from mock import patch +import time + +import opencas + + +@patch("opencas.cas_config.from_file") +def test_cas_settle_no_config(mock_config): + """ + Check if raises exception when no config is found + """ + + mock_config.side_effect = ValueError + + with pytest.raises(Exception): + opencas.wait_for_startup() + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_cores_didnt_start_01(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and waits for given time + + Single core in config, no devices in runtime config. + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(42, 13, "/dev/dummy") + ] + + time_start = time.time() + + result = opencas.wait_for_startup(timeout=5, interval=1) + + time_stop = time.time() + + assert len(result) == 1, "didn't return single uninitialized core" + assert ( + result[0].cache_id == 42 + and result[0].core_id == 13 + and result[0].device == "/dev/dummy" + ) + assert 4.5 < time_stop - time_start < 5.5, "didn't wait the right amount of time" + assert mock_list.call_count == 5 + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_cores_didnt_start_02(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and waits for given time + + Single device in config, one device in runtime config, but not the configured core + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy") + ] + + mock_list.return_value = [ + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Active", + "write policy": "wt", + "device": "-", + } + ] + + time_start = time.time() + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + time_stop = time.time() + + assert len(result) == 1, "didn't return uninitialized core" + assert 0.5 < time_stop - time_start < 1.5, "didn't wait the right amount of time" + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_cores_didnt_start_02(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and waits for given time + + The device waited for is in core pool. + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy") + ] + + mock_list.return_value = [ + { + "type": "core pool", + "id": "-", + "disk": "-", + "status": "-", + "write policy": "-", + "device": "-", + }, + { + "type": "core", + "id": "-", + "disk": "/dev/dummy", + "status": "Detached", + "write policy": "-", + "device": "-", + }, + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache", + "status": "Running", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "42", + "disk": "/dev/other_core", + "status": "Active", + "write policy": "-", + "device": "/dev/cas2-42", + }, + ] + + time_start = time.time() + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + time_stop = time.time() + + assert len(result) == 1, "didn't return uninitialized core" + assert 0.5 < time_stop - time_start < 1.5, "didn't wait the right amount of time" + # Assert the call count is within some small range in case something freezes up for a second + assert 9 <= mock_list.call_count <= 11 + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_cores_didnt_start_03(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and waits for given time + + The device waited for is not present, but its cache device is already started. + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy") + ] + + mock_list.return_value = [ + { + "type": "core pool", + "id": "-", + "disk": "-", + "status": "-", + "write policy": "-", + "device": "-", + }, + { + "type": "core", + "id": "-", + "disk": "/dev/other_core", + "status": "Detached", + "write policy": "-", + "device": "-", + }, + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Incomplete", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "42", + "disk": "/dev/dummy", + "status": "Inactive", + "write policy": "-", + "device": "/dev/cas1-42", + }, + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache2", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "3", + "disk": "/dev/dummy2", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-42", + }, + ] + + time_start = time.time() + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + time_stop = time.time() + + assert len(result) == 1, "didn't return uninitialized core" + assert 0.5 < time_stop - time_start < 1.5, "didn't wait the right amount of time" + # Assert the call count is within some small range in case something freezes up for a second + assert 9 <= mock_list.call_count <= 11 + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_cores_didnt_start_04(mock_list, mock_config): + """ + Check if properly returns uninitialized cores + + Two devices configured, both not present. + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy"), + opencas.cas_config.core_config(4, 44, "/dev/dosko"), + ] + + mock_list.return_value = [ + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Incomplete", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dummy", + "status": "Inactive", + "write policy": "-", + "device": "/dev/cas1-1", + }, + { + "type": "core", + "id": "2", + "disk": "/dev/dummy3", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-2", + }, + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache2", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "3", + "disk": "/dev/dummy2", + "status": "Active", + "write policy": "-", + "device": "/dev/cas2-3", + }, + ] + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + assert len(result) == 2, "didn't return uninitialized cores" + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_core_started_01(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and doesn't return initialized ones + + Two devices configured, one present, one not present. + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy"), + opencas.cas_config.core_config(4, 44, "/dev/dosko"), + ] + + mock_list.return_value = [ + { + "type": "core pool", + "id": "-", + "disk": "-", + "status": "-", + "write policy": "-", + "device": "-", + }, + { + "type": "core", + "id": "-", + "disk": "/dev/other_core", + "status": "Detached", + "write policy": "-", + "device": "-", + }, + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Incomplete", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dummy", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-1", + }, + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache2", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "3", + "disk": "/dev/dummy2", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-42", + }, + ] + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + assert len(result) == 1, "didn't return uninitialized core" + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_core_started_02(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and doesn't return initialized ones + + Two devices configured, both present and added. + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy"), + opencas.cas_config.core_config(4, 44, "/dev/dosko"), + ] + + mock_list.return_value = [ + { + "type": "core pool", + "id": "-", + "disk": "-", + "status": "-", + "write policy": "-", + "device": "-", + }, + { + "type": "core", + "id": "-", + "disk": "/dev/other_core", + "status": "Detached", + "write policy": "-", + "device": "-", + }, + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Running", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dummy", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-42", + }, + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache2", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "3", + "disk": "/dev/dummy2", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-42", + }, + { + "type": "cache", + "id": "4", + "disk": "/dev/dummy_cache4", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "44", + "disk": "/dev/dosko", + "status": "Active", + "write policy": "-", + "device": "/dev/cas4-44", + }, + ] + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + assert len(result) == 0, "no cores should remain uninitialized" + + +@patch("opencas.cas_config.from_file") +@patch("opencas.get_caches_list") +def test_cas_settle_core_started_03(mock_list, mock_config): + """ + Check if properly returns uninitialized cores and doesn't return initialized ones + + Two devices configured, simulate them gradually showing up with each call to + get_caches_list() + """ + + mock_config.return_value.get_startup_cores.return_value = [ + opencas.cas_config.core_config(1, 1, "/dev/dummy"), + opencas.cas_config.core_config(2, 1, "/dev/dosko"), + ] + + mock_list.side_effect = [ + [], + [ + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache4", + "status": "Incomplete", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dosko", + "status": "Inactive", + "write policy": "-", + "device": "/dev/cas2-1", + }, + ], + [ + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache4", + "status": "Incomplete", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dosko", + "status": "Inactive", + "write policy": "-", + "device": "/dev/cas2-1", + }, + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Incomplete", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dummy", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-1", + }, + ], + [ + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache4", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dosko", + "status": "Active", + "write policy": "-", + "device": "/dev/cas2-1", + }, + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Incomplete", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dummy", + "status": "Inactive", + "write policy": "-", + "device": "/dev/cas1-1", + }, + ], + [ + { + "type": "cache", + "id": "2", + "disk": "/dev/dummy_cache4", + "status": "Running", + "write policy": "wb", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dosko", + "status": "Active", + "write policy": "-", + "device": "/dev/cas2-1", + }, + { + "type": "cache", + "id": "1", + "disk": "/dev/dummy_cache", + "status": "Running", + "write policy": "wt", + "device": "-", + }, + { + "type": "core", + "id": "1", + "disk": "/dev/dummy", + "status": "Active", + "write policy": "-", + "device": "/dev/cas1-1", + }, + ], + ] + + result = opencas.wait_for_startup(timeout=1, interval=0.1) + + assert len(result) == 0, "no cores should remain uninitialized"