@@ -1850,6 +1850,165 @@ def ip_addr_check(session, mac_addr, ret_list, if_index, if_name):
1850
1850
if session_serial :
1851
1851
session_serial .close ()
1852
1852
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 via guest-agent 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:"
1968
+ " before=%s, after=%s" , initial_load , stress_load
1969
+ )
1970
+ except guest_agent .VAgentCmdError as e :
1971
+ test .fail (f"guest-get-load command failed: { e } " )
1972
+ else :
1973
+ # Initial load check
1974
+ error_context .context ("Check initial load average info" , LOG_JOB .info )
1975
+ guest_vals = _get_load_stats (session )
1976
+ qga_vals = _get_load_stats (session , False )
1977
+ prev_values = {"guest" : guest_vals , "qga" : qga_vals }
1978
+
1979
+ _log_load_values (guest_vals , qga_vals , "Initial" )
1980
+
1981
+ if errors := _verify_load_values (qga_vals , guest_vals ):
1982
+ test .fail ("Initial load check failed:\n " + "\n " .join (errors ))
1983
+
1984
+ # Stress test
1985
+ error_context .context ("Starting CPU stress test" , LOG_JOB .info )
1986
+ s , o = session .cmd_status_output (params ["cmd_install_stressng" ])
1987
+ if s != 0 :
1988
+ test .error (f"Failed to install stress-ng: { o } " )
1989
+ session .cmd (params ["cmd_run_stress" ])
1990
+ time .sleep (25 )
1991
+
1992
+ guest_vals = _get_load_stats (session )
1993
+ qga_vals = _get_load_stats (session , False )
1994
+
1995
+ _log_load_values (guest_vals , qga_vals , "Under stress" )
1996
+
1997
+ if errors := _verify_load_values (qga_vals , guest_vals , "increase" ):
1998
+ test .fail ("Stress test load check failed:\n " + "\n " .join (errors ))
1999
+
2000
+ prev_values = {"guest" : guest_vals , "qga" : qga_vals }
2001
+
2002
+ # sleep (60) wait for the stress-ng terminated.
2003
+ time .sleep (60 )
2004
+ guest_vals = _get_load_stats (session )
2005
+ qga_vals = _get_load_stats (session , False )
2006
+
2007
+ _log_load_values (guest_vals , qga_vals , "After stress" )
2008
+
2009
+ if errors := _verify_load_values (qga_vals , guest_vals , "decrease" ):
2010
+ test .fail ("Post-stress load check failed:\n " + "\n " .join (errors ))
2011
+
1853
2012
@error_context .context_aware
1854
2013
def gagent_check_reboot_shutdown (self , test , params , env ):
1855
2014
"""
0 commit comments