@@ -1850,6 +1850,166 @@ def ip_addr_check(session, mac_addr, ret_list, if_index, if_name):
18501850 if session_serial :
18511851 session_serial .close ()
18521852
1853+ @error_context .context_aware
1854+ def gagent_check_get_load (self , test , params , env ):
1855+ """
1856+ Test guest-get-load command functionality.
1857+
1858+ Steps:
1859+ 1) Get initial load values and verify qga/guest match
1860+ 2) Start stress test and verify load increases
1861+ 3) Stop stress test and verify load decreases
1862+
1863+ :param test: kvm test object
1864+ :param params: Dictionary with test parameters
1865+ :param env: Dictionary with test environment
1866+ """
1867+
1868+ def _get_load_stats (session , get_guest = True ):
1869+ """
1870+ Get load statistics from either guest OS or QGA.
1871+ Returns tuple of (1min, 5min, 15min) load values.
1872+ """
1873+ if get_guest :
1874+ try :
1875+ loads = session .cmd_output (params ["cmd_get_load" ]).strip ().split ()
1876+ return tuple (round (float (x ), 2 ) for x in loads [:3 ])
1877+ except (IndexError , ValueError ) as e :
1878+ test .error (f"Failed to get guest load stats: { e } " )
1879+ else :
1880+ try :
1881+ loads = self .gagent .get_load ()
1882+ load_keys = ("load1m" , "load5m" , "load15m" )
1883+ return tuple (round (float (loads [k ]), 2 ) for k in load_keys )
1884+ except (KeyError , ValueError ) as e :
1885+ test .error (f"Failed to get QGA load stats: { e } " )
1886+
1887+ def _verify_load_values (qga_vals , guest_vals , check_type = "match" ):
1888+ """
1889+ Compare load values between QGA and guest OS.
1890+ Also verifies if values changed as expected.
1891+ """
1892+ errors = []
1893+ periods = ["1-minute" , "5-minute" , "15-minute" ]
1894+
1895+ for period , qga , guest in zip (periods , qga_vals , guest_vals ):
1896+ if abs (qga - guest ) > 0.5 :
1897+ errors .append (
1898+ f"{ period } load mismatch: guest={ guest :.2f} , qga={ qga :.2f} "
1899+ )
1900+
1901+ # Only check load1m for increase/decrease
1902+ if check_type != "match" and prev_values :
1903+ qga_1m = qga_vals [0 ]
1904+ guest_1m = guest_vals [0 ]
1905+ prev_qga_1m = prev_values ["qga" ][0 ]
1906+ prev_guest_1m = prev_values ["guest" ][0 ]
1907+
1908+ if check_type == "increase" :
1909+ if qga_1m <= prev_qga_1m or guest_1m <= prev_guest_1m :
1910+ errors .append (
1911+ "1-minute load did not increase as expected:\n "
1912+ f"QGA: { prev_qga_1m :.2f} -> { qga_1m :.2f} \n "
1913+ f"Guest: { prev_guest_1m :.2f} -> { guest_1m :.2f} "
1914+ )
1915+ elif check_type == "decrease" :
1916+ if qga_1m >= prev_qga_1m or guest_1m >= prev_guest_1m :
1917+ errors .append (
1918+ "1-minute load did not decrease as expected:\n "
1919+ f"QGA: { prev_qga_1m :.2f} -> { qga_1m :.2f} \n "
1920+ f"Guest: { prev_guest_1m :.2f} -> { guest_1m :.2f} "
1921+ )
1922+
1923+ return errors
1924+
1925+ def _log_load_values (guest_vals , qga_vals , phase ):
1926+ """Log load values in a consistent format"""
1927+ LOG_JOB .info (
1928+ "%s load averages:\n Guest OS: %s\n QGA: %s" ,
1929+ phase ,
1930+ [f"{ x :.2f} " for x in guest_vals ],
1931+ [f"{ x :.2f} " for x in qga_vals ],
1932+ )
1933+
1934+ session = self ._get_session (params , self .vm )
1935+ self ._open_session_list .append (session )
1936+ prev_values = None
1937+
1938+ if params .get ("os_type" ) == "windows" :
1939+ error_context .context ("Get load info for Windows" , LOG_JOB .info )
1940+ try :
1941+ # Get initial load values
1942+ load_info = self .gagent .get_load ()
1943+ # Check if all required fields exist
1944+ for key in ["load1m" , "load5m" , "load15m" ]:
1945+ if key not in load_info :
1946+ test .fail (f"Missing { key } in guest-get-load return value" )
1947+ initial_load = load_info ["load1m" ]
1948+ LOG_JOB .info ("Initial load info from guest-agent: %s" , load_info )
1949+
1950+ # Start CPU stress test
1951+ error_context .context ("Start CPU stress test" , LOG_JOB .info )
1952+ session .cmd (params ["cmd_run_stress" ])
1953+ time .sleep (10 )
1954+
1955+ # Get load values after stress
1956+ load_info = self .gagent .get_load ()
1957+ stress_load = load_info ["load1m" ]
1958+ LOG_JOB .info ("Load info after stress: %s" , load_info )
1959+
1960+ # Verify load value changed
1961+ if stress_load <= initial_load :
1962+ test .fail (
1963+ f"Load value did not increase after CPU stress:"
1964+ f" before={ initial_load } , after={ stress_load } "
1965+ )
1966+ LOG_JOB .info (
1967+ "Load value increased as expected:" " before=%s, after=%s" ,
1968+ initial_load ,
1969+ stress_load ,
1970+ )
1971+ except guest_agent .VAgentCmdError as e :
1972+ test .fail (f"guest-get-load command failed: { e } " )
1973+ else :
1974+ # Initial load check
1975+ error_context .context ("Check initial load average info" , LOG_JOB .info )
1976+ guest_vals = _get_load_stats (session )
1977+ qga_vals = _get_load_stats (session , False )
1978+ prev_values = {"guest" : guest_vals , "qga" : qga_vals }
1979+
1980+ _log_load_values (guest_vals , qga_vals , "Initial" )
1981+
1982+ if errors := _verify_load_values (qga_vals , guest_vals ):
1983+ test .fail ("Initial load check failed:\n " + "\n " .join (errors ))
1984+
1985+ # Stress test
1986+ error_context .context ("Starting CPU stress test" , LOG_JOB .info )
1987+ s , o = session .cmd_status_output (params ["cmd_install_stressng" ])
1988+ if s != 0 :
1989+ test .error (f"Failed to install stress-ng: { o } " )
1990+ session .cmd (params ["cmd_run_stress" ])
1991+ time .sleep (25 )
1992+
1993+ guest_vals = _get_load_stats (session )
1994+ qga_vals = _get_load_stats (session , False )
1995+
1996+ _log_load_values (guest_vals , qga_vals , "Under stress" )
1997+
1998+ if errors := _verify_load_values (qga_vals , guest_vals , "increase" ):
1999+ test .fail ("Stress test load check failed:\n " + "\n " .join (errors ))
2000+
2001+ prev_values = {"guest" : guest_vals , "qga" : qga_vals }
2002+
2003+ # sleep (60) wait for the stress-ng terminated.
2004+ time .sleep (60 )
2005+ guest_vals = _get_load_stats (session )
2006+ qga_vals = _get_load_stats (session , False )
2007+
2008+ _log_load_values (guest_vals , qga_vals , "After stress" )
2009+
2010+ if errors := _verify_load_values (qga_vals , guest_vals , "decrease" ):
2011+ test .fail ("Post-stress load check failed:\n " + "\n " .join (errors ))
2012+
18532013 @error_context .context_aware
18542014 def gagent_check_reboot_shutdown (self , test , params , env ):
18552015 """
0 commit comments