mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-03-08 04:58:29 +03:00
systray: add a standalone window impl for uitests
This gives us as much coverage as possible without relying on too much host desktop config Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
parent
4348d4b128
commit
9b5d9eb9eb
15
tests/uitests/data/keyfile/systray.ini
Normal file
15
tests/uitests/data/keyfile/systray.ini
Normal file
@ -0,0 +1,15 @@
|
||||
[org/virt-manager/virt-manager]
|
||||
system-tray=true
|
||||
|
||||
manager-window-width=550
|
||||
manager-window-height=550
|
||||
|
||||
[org/virt-manager/virt-manager/connections]
|
||||
uris=['test:///default', 'foo:///']
|
||||
|
||||
[org/virt-manager/virt-manager/stats]
|
||||
update-interval=1
|
||||
|
||||
[org/virt-manager/virt-manager/vmlist-fields]
|
||||
disk-usage=false
|
||||
network-traffic=false
|
124
tests/uitests/test_systray.py
Normal file
124
tests/uitests/test_systray.py
Normal file
@ -0,0 +1,124 @@
|
||||
# This work is licensed under the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
import tests.utils
|
||||
from tests.uitests import utils as uiutils
|
||||
|
||||
|
||||
class Systray(uiutils.UITestCase):
|
||||
"""
|
||||
UI tests for virt-manager's systray using a fake testing backend
|
||||
"""
|
||||
|
||||
##############
|
||||
# Test cases #
|
||||
##############
|
||||
|
||||
def testSystrayFake(self):
|
||||
self.app.open(
|
||||
keyfile="systray.ini",
|
||||
extra_opts=["--test-options=fake-systray"],
|
||||
window_name="Virtual Machine Manager")
|
||||
|
||||
manager = self.app.topwin
|
||||
systray = self.app.root.find("vmm-fake-systray", check_active=False)
|
||||
uiutils.drag(manager, 1000, 1000)
|
||||
|
||||
# Add a connection to trigger systray update
|
||||
uri = tests.utils.URIs.kvm
|
||||
manager.find("File", "menu").click()
|
||||
manager.find("Add Connection...", "menu item").click()
|
||||
win = self.app.root.find_fuzzy("Add Connection", "dialog")
|
||||
win.combo_select("Hypervisor", "Custom URI")
|
||||
win.find("uri-entry", "text").set_text(uri)
|
||||
win.find("Connect", "push button").click()
|
||||
|
||||
# Hide the manager
|
||||
systray.click_title()
|
||||
systray.click()
|
||||
uiutils.check(lambda: not manager.showing)
|
||||
uiutils.check(lambda: self.app.is_running())
|
||||
|
||||
systray.click(button=3)
|
||||
menu = self.app.root.find("vmm-systray-menu")
|
||||
|
||||
def _get_conn_action(connstr, actionstr):
|
||||
if not menu.showing:
|
||||
systray.click(button=3)
|
||||
uiutils.check(lambda: menu.showing)
|
||||
connmenu = menu.find(connstr, "menu")
|
||||
connmenu.point()
|
||||
return connmenu.find(actionstr, "menu")
|
||||
|
||||
def _check_conn_action(connstr, actionstr):
|
||||
item = _get_conn_action(connstr, actionstr)
|
||||
uiutils.check(lambda: item.showing)
|
||||
systray.click(button=3)
|
||||
uiutils.check(lambda: not menu.showing)
|
||||
|
||||
def _do_conn_action(connstr, actionstr):
|
||||
item = _get_conn_action(connstr, actionstr)
|
||||
item.click()
|
||||
uiutils.check(lambda: not menu.showing)
|
||||
|
||||
def _get_vm_action(connstr, vmname, action):
|
||||
vmenu = _get_conn_action(connstr, vmname)
|
||||
vmenu.point()
|
||||
return vmenu.find(action, "menu")
|
||||
|
||||
def _check_vm_action(connstr, vmname, action):
|
||||
item = _get_vm_action(connstr, vmname, action)
|
||||
uiutils.check(lambda: item.showing)
|
||||
systray.click(button=3)
|
||||
uiutils.check(lambda: not menu.showing)
|
||||
|
||||
def _do_vm_action(connstr, vmname, action):
|
||||
item = _get_vm_action(connstr, vmname, action)
|
||||
item.click()
|
||||
uiutils.check(lambda: not menu.showing)
|
||||
|
||||
# Right click start a connection
|
||||
_check_conn_action("QEMU/KVM", "Disconnect")
|
||||
_do_conn_action("test default", "Connect")
|
||||
_check_conn_action("test default", "Disconnect")
|
||||
_do_conn_action("test testdriver", "Disconnect")
|
||||
_check_conn_action("test testdriver", "Connect")
|
||||
|
||||
# Trigger VM change
|
||||
_do_vm_action("QEMU/KVM", "test-arm-kernel", "Pause")
|
||||
_check_vm_action("QEMU/KVM", "test-arm-kernel", "Resume")
|
||||
|
||||
# Reshow the manager
|
||||
systray.click()
|
||||
uiutils.check(lambda: manager.showing)
|
||||
uiutils.check(lambda: self.app.is_running())
|
||||
|
||||
# Close from the menu
|
||||
systray.click_title()
|
||||
systray.click(button=3)
|
||||
menu = self.app.root.find("vmm-systray-menu")
|
||||
menu.find("Quit", "menu item").click()
|
||||
|
||||
uiutils.check(lambda: not self.app.is_running())
|
||||
|
||||
def testSystrayToggle(self):
|
||||
self.app.open(
|
||||
keyfile="systray.ini",
|
||||
extra_opts=["--test-options=fake-systray"],
|
||||
window_name="Virtual Machine Manager")
|
||||
|
||||
manager = self.app.topwin
|
||||
systray = self.app.root.find("vmm-fake-systray", check_active=False)
|
||||
manager.find("Edit", "menu").click()
|
||||
manager.find("Preferences", "menu item").click()
|
||||
prefs = self.app.root.find_fuzzy("Preferences", "frame")
|
||||
|
||||
# Close the system tray
|
||||
prefs.click_title()
|
||||
prefs.find_fuzzy("Enable system tray", "check").click()
|
||||
uiutils.check(lambda: not systray.showing)
|
||||
|
||||
# Close the manager
|
||||
manager.click_title()
|
||||
manager.keyCombo("<alt>F4")
|
||||
uiutils.check(lambda: not self.app.is_running())
|
@ -112,6 +112,7 @@ class CLITestOptionsClass:
|
||||
* fake-console-resolution: Fake viewer console resolution response.
|
||||
Spice doesn't return values here when we are just testing
|
||||
against seabios in uitests, this fakes it to hit more code paths
|
||||
* fake-systray: Enable the fake systray window
|
||||
"""
|
||||
def __init__(self, test_options_str):
|
||||
optset = set()
|
||||
@ -149,6 +150,7 @@ class CLITestOptionsClass:
|
||||
self.fake_systemd_success = _get("fake-systemd-success")
|
||||
self.fake_vnc_username = _get("fake-vnc-username")
|
||||
self.fake_console_resolution = _get("fake-console-resolution")
|
||||
self.fake_systray = _get("fake-systray")
|
||||
|
||||
if optset: # pragma: no cover
|
||||
raise RuntimeError("Unknown --test-options keys: %s" % optset)
|
||||
|
@ -19,7 +19,7 @@ from .connmanager import vmmConnectionManager
|
||||
try:
|
||||
# pylint: disable=ungrouped-imports
|
||||
from gi.repository import AppIndicator3
|
||||
except Exception:
|
||||
except Exception: # pragma: no cover
|
||||
AppIndicator3 = None
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ def _conn_disconnect_cb(src, uri):
|
||||
conn.close()
|
||||
|
||||
|
||||
def _has_appindicator_dbus():
|
||||
def _has_appindicator_dbus(): # pragma: no cover
|
||||
try:
|
||||
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
||||
dbus = Gio.DBusProxy.new_sync(bus, 0, None,
|
||||
@ -66,7 +66,7 @@ def _has_appindicator_dbus():
|
||||
|
||||
|
||||
_USING_APPINDICATOR = False
|
||||
if AppIndicator3:
|
||||
if AppIndicator3: # pragma: no cover
|
||||
if not _has_appindicator_dbus():
|
||||
log.debug("AppIndicator3 is available, but didn't "
|
||||
"find any dbus watcher.")
|
||||
@ -90,7 +90,7 @@ class _Systray(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class _SystrayIndicator(_Systray):
|
||||
class _SystrayIndicator(_Systray): # pragma: no cover
|
||||
"""
|
||||
UI backend for appindicator
|
||||
"""
|
||||
@ -121,7 +121,7 @@ class _SystrayIndicator(_Systray):
|
||||
self._icon.set_status(AppIndicator3.IndicatorStatus.PASSIVE)
|
||||
|
||||
|
||||
class _SystrayStatusIcon(_Systray):
|
||||
class _SystrayStatusIcon(_Systray): # pragma: no cover
|
||||
"""
|
||||
UI backend for Gtk StatusIcon
|
||||
"""
|
||||
@ -153,9 +153,45 @@ class _SystrayStatusIcon(_Systray):
|
||||
self._icon.set_visible(False)
|
||||
|
||||
|
||||
class _SystrayWindow(_Systray):
|
||||
"""
|
||||
A mock systray implementation that shows its own top level window,
|
||||
so we can test more of the infrastructure in our ui tests
|
||||
"""
|
||||
def __init__(self):
|
||||
self._window = None
|
||||
self._menu = None
|
||||
self._init_ui()
|
||||
|
||||
def _cmp(a, b):
|
||||
return ((a > b) - (a < b))
|
||||
def _init_ui(self):
|
||||
image = Gtk.Image()
|
||||
image.set_from_stock(Gtk.STOCK_ADD, Gtk.IconSize.DIALOG)
|
||||
|
||||
box = Gtk.EventBox()
|
||||
box.add(image)
|
||||
box.connect("button-press-event", self._popup_cb)
|
||||
|
||||
self._window = Gtk.Window()
|
||||
self._window.set_size_request(100, 100)
|
||||
self._window.get_accessible().set_name("vmm-fake-systray")
|
||||
self._window.add(box)
|
||||
|
||||
def is_embedded(self):
|
||||
return self._window.is_visible()
|
||||
|
||||
def set_menu(self, menu):
|
||||
self._menu = menu
|
||||
|
||||
def _popup_cb(self, src, event):
|
||||
if event.button == 1:
|
||||
_toggle_manager()
|
||||
else:
|
||||
self._menu.popup_at_pointer(event)
|
||||
|
||||
def show(self):
|
||||
self._window.show_all()
|
||||
def hide(self):
|
||||
self._window.hide()
|
||||
|
||||
|
||||
class _TrayMainMenu(vmmGObject):
|
||||
@ -183,6 +219,7 @@ class _TrayMainMenu(vmmGObject):
|
||||
Build the top level conn list menu when clicking the icon
|
||||
"""
|
||||
menu = Gtk.Menu()
|
||||
menu.get_accessible().set_name("vmm-systray-menu")
|
||||
menu.add(Gtk.SeparatorMenuItem())
|
||||
|
||||
exit_item = Gtk.ImageMenuItem.new_from_stock(Gtk.STOCK_QUIT, None)
|
||||
@ -362,7 +399,7 @@ class vmmSystray(vmmGObject):
|
||||
return cls._instance
|
||||
|
||||
@staticmethod
|
||||
def systray_disabled_message():
|
||||
def systray_disabled_message(): # pragma: no cover
|
||||
if "WAYLAND_DISPLAY" not in os.environ:
|
||||
return
|
||||
if _USING_APPINDICATOR:
|
||||
@ -389,8 +426,9 @@ class vmmSystray(vmmGObject):
|
||||
def _cleanup(self):
|
||||
self._hide_systray()
|
||||
self._systray = None
|
||||
self._mainmenu.cleanup()
|
||||
self._mainmenu = None
|
||||
if self._mainmenu:
|
||||
self._mainmenu.cleanup()
|
||||
self._mainmenu = None
|
||||
|
||||
|
||||
###########################
|
||||
@ -398,9 +436,6 @@ class vmmSystray(vmmGObject):
|
||||
###########################
|
||||
|
||||
def _init_mainmenu(self):
|
||||
if self._mainmenu:
|
||||
return
|
||||
|
||||
self._mainmenu = _TrayMainMenu()
|
||||
connmanager = vmmConnectionManager.get_instance()
|
||||
connmanager.connect("conn-added", self._conn_added_cb)
|
||||
@ -410,9 +445,11 @@ class vmmSystray(vmmGObject):
|
||||
|
||||
def _show_systray(self):
|
||||
if not self._systray:
|
||||
if _USING_APPINDICATOR:
|
||||
if self.config.CLITestOptions.fake_systray:
|
||||
self._systray = _SystrayWindow()
|
||||
elif _USING_APPINDICATOR: # pragma: no cover
|
||||
self._systray = _SystrayIndicator()
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
self._systray = _SystrayStatusIcon()
|
||||
self._init_mainmenu()
|
||||
self._systray.set_menu(self._mainmenu.get_menu())
|
||||
|
Loading…
x
Reference in New Issue
Block a user