1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-02-04 07:51:50 +00:00
community.general/tests/unit/plugins/modules/test_pmem.py
2025-11-01 13:46:53 +01:00

732 lines
25 KiB
Python

# Copyright (c) 2022, Masayoshi Mizuma <msys.mizuma@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
import pytest
import json
from unittest.mock import patch
pytest.importorskip("xmltodict")
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
ModuleTestCase,
set_module_args,
AnsibleFailJson,
AnsibleExitJson,
)
from ansible_collections.community.general.plugins.modules import pmem as pmem_module
# goal_plain: the mock return value of pmem_run_command with:
# impctl create -goal MemoryMode=70 Reserved=20 PersistentMemoryType=AppDirect
goal_plain = """The following configuration will be applied:
SocketID | DimmID | MemorySize | AppDirect1Size | AppDirect2Size
==================================================================
0x0000 | 0x0001 | 88.000 GiB | 12.000 GiB | 0.000 GiB
0x0000 | 0x0011 | 88.000 GiB | 12.000 GiB | 0.000 GiB
0x0001 | 0x1001 | 88.000 GiB | 12.000 GiB | 0.000 GiB
0x0001 | 0x1011 | 88.000 GiB | 12.000 GiB | 0.000 GiB
Do you want to continue? [y/n] Error: Invalid data input."""
# goal_plain_sk0: the mock return value of pmem_run_command with:
# ipmctl create -goal -socket 0 MemoryMode=70 Reserved=20 PersistentMemoryType=AppDirect
goal_plain_sk0 = """The following configuration will be applied:
SocketID | DimmID | MemorySize | AppDirect1Size | AppDirect2Size
==================================================================
0x0000 | 0x0001 | 88.000 GiB | 12.000 GiB | 0.000 GiB
0x0000 | 0x0011 | 88.000 GiB | 12.000 GiB | 0.000 GiB
Do you want to continue? [y/n] Error: Invalid data input."""
# goal_plain_sk1: the mock return value of pmem_run_command with:
# ipmctl create -goal -socket 1 MemoryMode=70 Reserved=20 PersistentMemoryType=AppDirect
goal_plain_sk1 = """The following configuration will be applied:
SocketID | DimmID | MemorySize | AppDirect1Size | AppDirect2Size
==================================================================
0x0001 | 0x1001 | 88.000 GiB | 12.000 GiB | 0.000 GiB
0x0001 | 0x1011 | 88.000 GiB | 12.000 GiB | 0.000 GiB
Do you want to continue? [y/n] Error: Invalid data input."""
# goal: the mock return value of pmem_run_command with:
# ipmctl create -u B -o nvmxml -force -goal -socket 0 MemoryMode=70 Reserved=20 PersistentMemoryType=AppDirect
goal = """<?xml version="1.0"?>
<ConfigGoalList>
<ConfigGoal>
<SocketID>0x0000</SocketID>
<DimmID>0x0001</DimmID>
<MemorySize>94489280512 B</MemorySize>
<AppDirect1Size>12884901888 B</AppDirect1Size>
<AppDirect2Size>0 B</AppDirect2Size>
</ConfigGoal>
<ConfigGoal>
<SocketID>0x0000</SocketID>
<DimmID>0x0011</DimmID>
<MemorySize>94489280512 B</MemorySize>
<AppDirect1Size>12884901888 B</AppDirect1Size>
<AppDirect2Size>0 B</AppDirect2Size>
</ConfigGoal>
</ConfigGoalList>"""
# goal_sk0: the mock return value of pmem_run_command with:
# ipmctl create -u B -o nvmxml -force -goal -socket 0 MemoryMode=70 Reserved=20 PersistentMemoryType=AppDirect
goal_sk0 = """<?xml version="1.0"?>
<ConfigGoalList>
<ConfigGoal>
<SocketID>0x0000</SocketID>
<DimmID>0x0001</DimmID>
<MemorySize>94489280512 B</MemorySize>
<AppDirect1Size>12884901888 B</AppDirect1Size>
<AppDirect2Size>0 B</AppDirect2Size>
</ConfigGoal>
<ConfigGoal>
<SocketID>0x0001</SocketID>
<DimmID>0x0011</DimmID>
<MemorySize>94489280512 B</MemorySize>
<AppDirect1Size>12884901888 B</AppDirect1Size>
<AppDirect2Size>0 B</AppDirect2Size>
</ConfigGoal>
</ConfigGoalList>"""
# goal_sk1: the mock return value of pmem_run_command with:
# ipmctl create -u B -o nvmxml -force -goal -socket 1 MemoryMode=70 Reserved=20 PersistentMemoryType=AppDirect
goal_sk1 = """<?xml version="1.0"?>
<ConfigGoalList>
<ConfigGoal>
<SocketID>0x0001</SocketID>
<DimmID>0x1001</DimmID>
<MemorySize>94489280512 B</MemorySize>
<AppDirect1Size>12884901888 B</AppDirect1Size>
<AppDirect2Size>0 B</AppDirect2Size>
</ConfigGoal>
<ConfigGoal>
<SocketID>0x0001</SocketID>
<DimmID>0x1011</DimmID>
<MemorySize>94489280512 B</MemorySize>
<AppDirect1Size>12884901888 B</AppDirect1Size>
<AppDirect2Size>0 B</AppDirect2Size>
</ConfigGoal>
</ConfigGoalList>"""
# dimmlist: the mock return value of pmem_run_command with:
# ipmctl show -d Capacity -u B -o nvmxml -dimm
dimmlist = """<?xml version="1.0"?>
<DimmList>
<Dimm>
<DimmID>0x0001</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
<Dimm> <DimmID>0x0011</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
<Dimm>
<DimmID>0x1001</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
<Dimm> <DimmID>0x1011</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
</DimmList>"""
# dimmlist_sk0: the mock return value of pmem_run_command with:
# ipmctl show -d Capacity -u B -o nvmxml -dimm -socket 0
dimmlist_sk0 = """<?xml version="1.0"?>
<DimmList>
<Dimm>
<DimmID>0x0001</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
<Dimm> <DimmID>0x0011</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
</DimmList>"""
# dimmlist_sk1: the mock return value of pmem_run_command with:
# ipmctl show -d Capacity -u B -o nvmxml -dimm -socket 1
dimmlist_sk1 = """<?xml version="1.0"?>
<DimmList>
<Dimm>
<DimmID>0x1001</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
<Dimm> <DimmID>0x1011</DimmID>
<Capacity>135744782336 B</Capacity>
</Dimm>
</DimmList>"""
# show_skt: the mock return value of pmem_run_command with:
# ipmctl show -o nvmxml -socket
show_skt = """<?xml version="1.0"?>
<SocketList>
<Socket>
<SocketID>0x0000</SocketID>
<MappedMemoryLimit>1024.000 GiB</MappedMemoryLimit>
<TotalMappedMemory>400.000 GiB</TotalMappedMemory>
</Socket>
<Socket>
<SocketID>0x0001</SocketID>
<MappedMemoryLimit>1024.000 GiB</MappedMemoryLimit>
<TotalMappedMemory>400.000 GiB</TotalMappedMemory>
</Socket>
</SocketList>"""
# ndctl_region: the mock return value of pmem_run_command with:
# ndctl list -R
ndctl_region = """[
{
"dev":"region1",
"size":51539607552,
"align":16777216,
"available_size":50465865728,
"max_available_extent":50465865728,
"type":"pmem",
"iset_id":4694373484956518536,
"persistence_domain":"memory_controller"
},
{
"dev":"region0",
"size":51539607552,
"align":16777216,
"available_size":51539607552,
"max_available_extent":51539607552,
"type":"pmem",
"iset_id":4588538894081362056,
"persistence_domain":"memory_controller"
}
]"""
# ndctl_region_empty: the mock return value of pmem_run_command with:
# ndctl list -R
ndctl_region_empty = ""
# ndctl_without_size: the mock return value of pmem_run_command with:
# ndctl create-namespace -t pmem -m sector
ndctl_create_without_size = """{
"dev":"namespace1.0",
"mode":"sector",
"size":"47.95 GiB (51.49 GB)",
"uuid":"1aca23a5-941c-4f4a-9d88-e531f0b5a27e",
"sector_size":4096,
"blockdev":"pmem1s"
}"""
# ndctl_list_N: the mock return value of pmem_run_command with:
# ndctl list -N
ndctl_list_N = """[
{
"dev":"namespace1.0",
"mode":"sector",
"size":51488243712,
"uuid":"1aca23a5-941c-4f4a-9d88-e531f0b5a27e",
"sector_size":4096,
"blockdev":"pmem1s"
}
]"""
# ndctl_result_1G: the mock return value of pmem_run_command with:
# ndctl create-namespace -t pmem -m sector -s 1073741824
ndctl_create_1G = """{
"dev":"namespace0.0",
"mode":"sector",
"size":"1021.97 MiB (1071.62 MB)",
"uuid":"5ba4e51b-3028-4b06-8495-b6834867a9af",
"sector_size":4096,
"blockdev":"pmem0s"
}"""
# ndctl_result_640M: the mock return value of pmem_run_command with:
# ndctl create-namespace -t pmem -m raw -s 671088640
ndctl_create_640M = """{
"dev":"namespace1.0",
"mode":"raw",
"size":"640.00 MiB (671.09 MB)",
"uuid":"5ac1f81d-86e6-4f07-9460-8c4d37027f7a",
"sector_size":512,
"blockdev":"pmem1"
}"""
# ndctl_list_N_tow_namespaces: the mock return value of pmem_run_command with:
# ndctl list -N
ndctl_list_N_two_namespaces = """[
{
"dev":"namespace1.0",
"mode":"sector",
"size":1071616000,
"uuid":"afcf050d-3a8b-4f48-88a5-16d7c40ab2d8",
"sector_size":4096,
"blockdev":"pmem1s"
},
{
"dev":"namespace1.1",
"mode":"raw",
"size":671088640,
"uuid":"fb704339-729b-4cc7-b260-079f2633d84f",
"sector_size":512,
"blockdev":"pmem1.1"
}
]"""
class TestPmem(ModuleTestCase):
def setUp(self):
super().setUp()
self.module = pmem_module
self.mock_run_command = patch("ansible.module_utils.basic.AnsibleModule.run_command")
self.mock_get_bin_path = patch("ansible.module_utils.basic.AnsibleModule.get_bin_path")
self.run_command = self.mock_run_command.start()
self.get_bin_path = self.mock_get_bin_path.start()
self.mock_pmem_is_dcpmm_installed = patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_is_dcpmm_installed",
return_value="",
)
self.mock_pmem_init_env = patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_init_env", return_value=""
)
self.pmem_is_dcpmm_installed = self.mock_pmem_is_dcpmm_installed.start()
self.pmem_init_env = self.mock_pmem_init_env.start()
def tearDown(self):
super().tearDown()
self.mock_get_bin_path.stop()
self.mock_run_command.stop()
self.mock_pmem_is_dcpmm_installed.stop()
self.mock_pmem_init_env.stop()
def result_check(self, result, socket, appdirect, memmode, reserved):
self.assertTrue(result.exception.args[0]["changed"])
self.assertTrue(result.exception.args[0]["reboot_required"])
test_result = result.exception.args[0]["result"]
if socket:
maxIndex = 1
else:
maxIndex = 0
for i in range(0, maxIndex):
self.assertAlmostEqual(test_result[i]["appdirect"], appdirect[i])
self.assertAlmostEqual(test_result[i]["memorymode"], memmode[i])
self.assertAlmostEqual(test_result[i]["reserved"], reserved[i])
if socket:
self.assertAlmostEqual(test_result[i]["socket"], i)
def result_check_ns(self, result, namespace):
self.assertTrue(result.exception.args[0]["changed"])
self.assertFalse(result.exception.args[0]["reboot_required"])
test_result = result.exception.args[0]["result"]
expected = json.loads(namespace)
for i, result in enumerate(test_result):
self.assertEqual(result["dev"], expected[i]["dev"])
self.assertEqual(result["size"], expected[i]["size"])
def test_fail_when_required_args_missing(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args({}):
pmem_module.main()
def test_fail_when_appdirect_only(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"appdirect": 10,
}
):
pmem_module.main()
def test_fail_when_MemosyMode_only(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"memorymode": 70,
}
):
pmem_module.main()
def test_fail_when_reserved_only(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"reserved": 10,
}
):
pmem_module.main()
def test_fail_when_appdirect_memorymode_reserved_total_not_100(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"appdirect": 10,
"memorymode": 70,
"reserved": 10,
}
):
pmem_module.main()
def test_when_appdirect_memorymode(self):
with set_module_args(
{
"appdirect": 10,
"memorymode": 70,
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[goal_plain, goal, dimmlist],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check(result, False, [25769803776], [188978561024], [328230764544])
def test_when_appdirect_memorymode_reserved(self):
with set_module_args(
{
"appdirect": 10,
"memorymode": 70,
"reserved": 20,
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[goal_plain, goal, dimmlist],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check(result, False, [25769803776], [188978561024], [328230764544])
def test_when_appdirect_notinterleaved_memorymode_reserved(self):
with set_module_args(
{
"appdirect": 10,
"appdirect_interleaved": False,
"memorymode": 70,
"reserved": 20,
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[goal_plain, goal, dimmlist],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check(result, False, [25769803776], [188978561024], [328230764544])
def test_fail_when_socket_id_appdirect(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"socket": [
{
"id": 0,
"appdirect": 10,
},
{
"id": 1,
"appdirect": 10,
},
],
}
):
pmem_module.main()
def test_fail_when_socket0_id_memorymode_socket1_id_appdirect(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"socket": [
{
"id": 0,
" memorymode": 70,
},
{
"id": 1,
"appdirect": 10,
},
],
}
):
pmem_module.main()
def test_fail_when_socket0_without_id(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"socket": [
{
"appdirect": 10,
"memorymode": 70,
},
{
"id": 1,
"appdirect": 10,
"memorymode": 70,
},
],
}
):
pmem_module.main()
def test_when_socket0_and_1_appdirect_memorymode(self):
with set_module_args(
{
"socket": [
{
"id": 0,
"appdirect": 10,
"memorymode": 70,
},
{
"id": 1,
"appdirect": 10,
"memorymode": 70,
},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[show_skt, goal_plain_sk0, goal_sk0, dimmlist_sk0, goal_plain_sk1, goal_sk1, dimmlist_sk1],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check(
result, True, [12884901888, 12884901888], [94489280512, 94489280512], [164115382272, 164115382272]
)
def test_when_socket0_and_1_appdirect_memorymode_reserved(self):
with set_module_args(
{
"socket": [
{
"id": 0,
"appdirect": 10,
"memorymode": 70,
"reserved": 20,
},
{
"id": 1,
"appdirect": 10,
"memorymode": 70,
"reserved": 20,
},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[show_skt, goal_plain_sk0, goal_sk0, dimmlist_sk0, goal_plain_sk1, goal_sk1, dimmlist_sk1],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check(
result, True, [12884901888, 12884901888], [94489280512, 94489280512], [164115382272, 164115382272]
)
def test_when_socket0_appdirect_notinterleaved_memorymode_reserved_socket1_appdirect_memorymode_reserved(self):
with set_module_args(
{
"socket": [
{
"id": 0,
"appdirect": 10,
"appdirect_interleaved": False,
"memorymode": 70,
"reserved": 20,
},
{
"id": 1,
"appdirect": 10,
"memorymode": 70,
"reserved": 20,
},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[show_skt, goal_plain_sk0, goal_sk0, dimmlist_sk0, goal_plain_sk1, goal_sk1, dimmlist_sk1],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check(
result, True, [12884901888, 12884901888], [94489280512, 94489280512], [164115382272, 164115382272]
)
def test_fail_when_namespace_without_mode(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{
"size": "1GB",
"type": "pmem",
},
{
"size": "2GB",
"type": "blk",
},
],
}
):
pmem_module.main()
def test_fail_when_region_is_empty(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{
"size": "1GB",
"type": "pmem",
"mode": "sector",
},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region_empty],
):
pmem_module.main()
def test_fail_when_namespace_invalid_size(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{
"size": "1XXX",
"type": "pmem",
"mode": "sector",
},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region],
):
pmem_module.main()
def test_fail_when_size_is_invalid_alignment(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{"size": "400MB", "type": "pmem", "mode": "sector"},
{"size": "500MB", "type": "pmem", "mode": "sector"},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region],
):
pmem_module.main()
def test_fail_when_blk_is_unsupported_type(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{"size": "4GB", "type": "pmem", "mode": "sector"},
{"size": "5GB", "type": "blk", "mode": "sector"},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region],
):
pmem_module.main()
def test_fail_when_size_isnot_set_to_multiple_namespaces(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{"type": "pmem", "mode": "sector"},
{"size": "500GB", "type": "blk", "mode": "sector"},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region],
):
pmem_module.main()
def test_fail_when_size_of_namespace_over_available(self):
with self.assertRaises(AnsibleFailJson):
with set_module_args(
{
"namespace": [
{"size": "400GB", "type": "pmem", "mode": "sector"},
{"size": "500GB", "type": "pmem", "mode": "sector"},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region],
):
pmem_module.main()
def test_when_namespace0_without_size(self):
with set_module_args(
{
"namespace": [
{"type": "pmem", "mode": "sector"},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region, ndctl_create_without_size, ndctl_list_N],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check_ns(result, ndctl_list_N)
def test_when_namespace0_with_namespace_append(self):
with set_module_args(
{
"namespace": [
{"size": "640MB", "type": "pmem", "mode": "raw"},
],
"namespace_append": True,
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region, ndctl_create_640M, ndctl_list_N_two_namespaces],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check_ns(result, ndctl_list_N_two_namespaces)
def test_when_namespace0_1GiB_pmem_sector_namespace1_640MiB_pmem_raw(self):
with set_module_args(
{
"namespace": [
{"size": "1GB", "type": "pmem", "mode": "sector"},
{
"size": "640MB",
"type": "pmem",
"mode": "raw",
},
],
}
):
with patch(
"ansible_collections.community.general.plugins.modules.pmem.PersistentMemory.pmem_run_command",
side_effect=[ndctl_region, ndctl_create_1G, ndctl_create_640M, ndctl_list_N_two_namespaces],
):
with self.assertRaises(AnsibleExitJson) as result:
pmem_module.main()
self.result_check_ns(result, ndctl_list_N_two_namespaces)