diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 00000000000..22bdf5588e9
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1695697420351
+
+
+ 1695697420351
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py
+ 127
+
+
+
+ file://$PROJECT_DIR$/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py
+ 119
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libvirt/tests/cfg/memory/memory_balloon/period_config_of_memory_balloon.cfg b/libvirt/tests/cfg/memory/memory_balloon/period_config_of_memory_balloon.cfg
new file mode 100644
index 00000000000..a656cb52c45
--- /dev/null
+++ b/libvirt/tests/cfg/memory/memory_balloon/period_config_of_memory_balloon.cfg
@@ -0,0 +1,33 @@
+- memory.balloon.period:
+ type = period_config_of_memory_balloon
+ start_vm = no
+ mem_unit = "KiB"
+ current_mem_unit = "KiB"
+ current_mem = "2097152"
+ mem_value = "2097152"
+ mem_operation = "swapoff -a; dd if=/dev/zero of=/tmp/temp bs=1024K count=10; memhog -r5 500M"
+ variants:
+ - virtio_model:
+ memballoon_model = "virtio"
+ - virtio_trans_model:
+ memballoon_model = "virtio-transitional"
+ - virtio_non_trans_model:
+ memballoon_model = "virtio-non-transitional"
+ variants:
+ - undefined_period:
+ period_value_1 = "undefined"
+ period_attr = ""
+ xpath = [{'element_attrs': [".//memballoon/stats"]}]
+ xpath_ignore = True
+ period_value_2 = "0"
+ period_cmd = "--period ${period_value_2}"
+ - int_period:
+ period_value_1 = "2"
+ period_attr = ",'stats_period':'${period_value_1}'"
+ xpath = [{'element_attrs': [".//stats[@period='${period_value_1}']"]}]
+ period_value_2 = "0"
+ period_cmd = "--period ${period_value_2}"
+ device_dict = "{'model':'${memballoon_model}' ${period_attr}}"
+ variants:
+ - memory_allocation:
+ mem_attrs = {'memory_unit':'${mem_unit}','memory':${mem_value},'current_mem':${current_mem},'current_mem_unit':'${current_mem_unit}'}
diff --git a/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py b/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py
new file mode 100644
index 00000000000..c8125eca663
--- /dev/null
+++ b/libvirt/tests/src/memory/memory_balloon/period_config_of_memory_balloon.py
@@ -0,0 +1,172 @@
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Copyright Redhat
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Author: Nannan Li
+#
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+import re
+import time
+
+from virttest import virsh
+
+from virttest.libvirt_xml import vm_xml
+from virttest.libvirt_xml.devices import memballoon
+from virttest.utils_libvirt import libvirt_vmxml
+
+
+def run(test, params, env):
+ """
+ Verify memory statistics config "period" takes effect with various memory balloon models
+
+ Scenario:
+ 1.memory balloon models: virtio, virtio-transitional, virtio-non-transitional.
+ 2.period: int period, undefined.
+ 3.mem config: mem, current mem.
+ """
+
+ def check_same_value(value1, value2, log_msg):
+ """
+ This function checks whether two values are same or not.
+
+ :param value1: First value to be checked.
+ :param value2: Second value to be checked.
+ :param log_msg: Log message to display in case of failure.
+ :raises: Test.Fail if values are not same.
+ """
+ if value1 != value2:
+ test.fail("The %s should not change from '%s' to '%s'"
+ % (log_msg, value1, value2))
+
+ def get_memory_statistics():
+ """
+ Get memory statistics by virsh dommemstat
+
+ :return: usable mem, last_update, disk_caches value in result.
+ """
+ # Sleep some seconds to get virsh dommemstat
+
+ for wait in range(0, 5):
+ # wait for max 25s to check dommemstat result
+ res = virsh.dommemstat(vm_name, ignore_status=False,
+ debug=True).stdout_text
+ if not re.findall(r'usable (\d+)', res):
+ time.sleep(5)
+ else:
+ usable_mem = re.findall(r'usable (\d+)', res)[0]
+ last_update = re.findall(r'last_update (\d+)', res)[0]
+ disk_caches = re.findall(r'disk_caches (\d+)', res)[0]
+
+ return usable_mem, last_update, disk_caches
+
+ def check_vm_dommemstat(period_config, usable_mem, last_update,
+ disk_caches):
+ """
+ Check correct vm dommemstat result.
+
+ :params: period_config: period config, undefined , 0 or number
+ :params: usable_mem, the usable mem value before consume mem
+ :params: last_update, the last update value before consume mem
+ :params: disk_caches, the disk caches value before consume mem
+ """
+ usable_mem_new, last_update_new, disk_caches_new = get_memory_statistics()
+
+ if period_config in ["undefined", "0"]:
+ check_same_value(usable_mem_new, usable_mem, "usable value")
+ check_same_value(last_update_new, last_update, "last update")
+ check_same_value(disk_caches_new, disk_caches, "disk caches")
+
+ elif period_config.isdigit() and period_config.isdigit() != "0":
+ if usable_mem_new == usable_mem:
+ test.fail("The usable mem should be as '%s' instead of '%s'"
+ % (usable_mem_new, usable_mem))
+ if last_update_new <= last_update:
+ test.fail("The last update '%s' should bigger than to '%s'"
+ % (last_update_new, last_update))
+ if disk_caches_new == disk_caches:
+ test.fail("The disk caches mem '%s' should not same as '%s' " %
+ (disk_caches_new, disk_caches))
+
+ def run_test():
+ """
+ Define and start guest
+ Check memTotal and memory allocation
+ """
+ test.log.info("TEST_STEP1: Define guest")
+ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name)
+
+ vmxml.del_device('memballoon', by_tag=True)
+ mem_balloon = memballoon.Memballoon()
+ mem_balloon.setup_attrs(**device_dict)
+ vmxml.devices = vmxml.devices.append(mem_balloon)
+
+ vmxml.setup_attrs(**mem_attrs)
+ vmxml.sync()
+
+ test.log.info("TEST_STEP2: Start guest ")
+ if not vm.is_alive():
+ vm.start()
+ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name)
+ test.log.debug("After start vm, get xml is:\n%s", vmxml)
+
+ test.log.info("TEST_STEP3: Check memory balloon config by virsh dumpxml")
+ if libvirt_vmxml.check_guest_xml_by_xpaths(
+ vmxml, expect_xpath, xpath_ignore) == xpath_ignore:
+ test.fail("Expect to get '%s' in xml result is '%s'" % (expect_xpath, xpath_ignore))
+
+ test.log.info("TEST_STEP4: Get vm memory statistics by virsh dommemstat")
+ usable_mem_1, last_update_1, disk_caches_1 = get_memory_statistics()
+
+ test.log.info("TEST_STEP5: Do memory operation and check dommemstat")
+ session = vm.wait_for_login()
+ status, stdout = session.cmd_status_output(mem_operation)
+ session.close()
+ if status:
+ test.fail("Failed to consume memory:%s" % stdout)
+ check_vm_dommemstat(period_value_1, usable_mem_1, last_update_1, disk_caches_1)
+
+ test.log.info("TEST_STEP6: Change the period setting")
+ virsh.dommemstat(vm_name, period_cmd, ignore_status=False, debug=True)
+
+ test.log.info("TEST_STEP7: Repeat consume mem and check memory "
+ "statistics step")
+ if libvirt_vmxml.check_guest_xml_by_xpaths(
+ vmxml, expect_xpath, xpath_ignore) == xpath_ignore:
+ test.fail("Expect to get '%s' in xml is '%s'" % (expect_xpath, xpath_ignore))
+
+ usable_mem_3, last_update_3, disk_caches_3 = get_memory_statistics()
+ session = vm.wait_for_login()
+ status, stdout = session.cmd_status_output(mem_operation)
+ session.close()
+ if status:
+ test.fail("Failed to consume memory:%s" % stdout)
+ check_vm_dommemstat(period_value_2, usable_mem_3, last_update_3, disk_caches_3)
+
+ def teardown_test():
+ """
+ Clean data.
+ """
+ test.log.info("TEST_TEARDOWN: Clean up env.")
+ bkxml.sync()
+
+ vm_name = params.get("main_vm")
+ vm = env.get_vm(vm_name)
+ vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
+ bkxml = vmxml.copy()
+
+ mem_attrs = eval(params.get("mem_attrs", "{}"))
+ device_dict = eval(params.get("device_dict", "{}"))
+ mem_operation = params.get("mem_operation")
+ period_value_1 = params.get("period_value_1")
+ period_value_2 = params.get("period_value_2")
+ period_cmd = params.get("period_cmd")
+ expect_xpath = eval(params.get("xpath"))
+ xpath_ignore = bool(params.get("xpath_ignore", False))
+
+ try:
+ run_test()
+
+ finally:
+ teardown_test()