/* Copyright (c) Citrix Systems Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System.Collections.Generic; using System.Threading; using System.Windows.Forms; using NUnit.Framework; using XenAdmin; using XenAdmin.Controls; using XenAdmin.Core; using XenAPI; namespace XenAdminTests.TabsAndMenus { public class TabsAndMenus : MainWindowLauncher_TestFixture { protected bool CheckHelp = true; public TabsAndMenus(params string[] databases) : base(databases) { } protected void VerifyTabs(object ixmo, string[] expectedTabs) { string ixmoString = (ixmo == null ? "XenCenter node" : ixmo.ToString()); // Select the ixmo in the tree Assert.IsTrue(SelectInTree(ixmo), "Couldn't find a node for " + ixmoString + " in the tree"); // Check that we have the right number of tabs TabControl actualTabs = Program.MainWindow.TheTabControl; Assert.AreEqual(expectedTabs.Length, actualTabs.TabPages.Count, "Didn't find the expected number of tabs for " + ixmoString); for (int i = 0; i < expectedTabs.Length; ++i) { //// Select the i'th tab and check that the tab has the right name string actualText = actualTabs.TabPages[i].Text; Assert.AreEqual(expectedTabs[i], actualText, "Tab wrong at position " + i + " for " + ixmoString); if (CheckHelp) { // Make sure we have help bool hasHelp = MW(Program.MainWindow.HasHelp); Assert.IsTrue(hasHelp, "No help for tab " + expectedTabs[i] + " for " + ixmoString); } } } // In the expected items, represent a separator by a null protected void VerifyContextMenu(object ixmo, ExpectedMenuItem[] expectedItems) { string ixmoString = (ixmo == null ? "XenCenter node" : ixmo.ToString()); // The easiest way to generate the context menu is to call TreeView_NodeMouseClick_ ourselves. // So construct fake click event data. VirtualTreeNode node = FindInTree(ixmo); Assert.IsNotNull(node, "Couldn't find a node for " + ixmoString + " in the tree"); VirtualTreeNodeMouseClickEventArgs e = new VirtualTreeNodeMouseClickEventArgs(node, MouseButtons.Right, 1, 0, 0); // Generate the TreeContextMenu MW(() => { node.EnsureVisible(); var view = TestUtils.GetNavigationView(MainWindowWrapper.Item, "navigationPane.navigationView"); TestUtils.ExecuteMethod(view, "HandleNodeRightClick", new object[] { e }); }); var menu = TestUtils.GetContextMenuStrip(MainWindowWrapper.Item, "navigationPane.navigationView.TreeContextMenu"); AssertToolStripItems(ixmoString, expectedItems, menu.Items, true); // Close the menu again MW(menu.Close); Thread.Sleep(100); } protected void VerifyToolbar(object ixmo, ExpectedMenuItem[] expectedItems) { string ixmoString = (ixmo == null ? "XenCenter node" : ixmo.ToString()); // Select the ixmo in the tree Assert.IsTrue(SelectInTree(ixmo), "Couldn't find a node for " + ixmoString + " in the tree"); List items = new List(); // skip out forward, back and system alert buttons for (int i = 2; i < MainWindowWrapper.MainToolStrip.Items.Count; i++) items.Add(MainWindowWrapper.MainToolStrip.Items[i]); AssertToolStripItems(ixmoString, expectedItems, new ToolStripItemCollection(MainWindowWrapper.MainToolStrip, items.ToArray()), false); } /// /// Verifies the toolbar for the currently selected item. /// protected void VerifyToolbar(ExpectedMenuItem[] expectedItems) { List items = new List(); // skip out forward, back and system alert buttons for (int i = 2; i < MainWindowWrapper.MainToolStrip.Items.Count - 1; i++) { items.Add(MainWindowWrapper.MainToolStrip.Items[i]); } AssertToolStripItems(MainWindowWrapper.TreeView.SelectedNode.Text, expectedItems, new ToolStripItemCollection(MainWindowWrapper.MainToolStrip, items.ToArray()), false); } protected void VerifyMainMenu(object ixmo, ExpectedMenuItem[] poolMenu, ExpectedMenuItem[] serverMenu, ExpectedMenuItem[] vmMenu, ExpectedMenuItem[] storageMenu, ExpectedMenuItem[] templatesMenu) { string ixmoString = (ixmo == null ? "XenCenter node" : ixmo.ToString()); // Select the ixmo in the tree Assert.IsTrue(SelectInTree(ixmo), "Couldn't find a node for " + ixmoString + " in the tree"); Thread.Sleep(300); MW(MainWindowWrapper.PoolMenu.Select); MW(MainWindowWrapper.PoolMenu.ShowDropDown); Thread.Sleep(100); AssertToolStripItems(ixmoString, poolMenu, MainWindowWrapper.PoolMenu.DropDownItems, true); MW(MainWindowWrapper.PoolMenu.HideDropDown); MW(MainWindowWrapper.HostMenu.Select); MW(MainWindowWrapper.HostMenu.ShowDropDown); Thread.Sleep(100); AssertToolStripItems(ixmoString, serverMenu, MainWindowWrapper.HostMenu.DropDownItems, true); MW(MainWindowWrapper.HostMenu.HideDropDown); MW(MainWindowWrapper.VMMenu.Select); MW(MainWindowWrapper.VMMenu.ShowDropDown); Thread.Sleep(100); AssertToolStripItems(ixmoString, vmMenu, MainWindowWrapper.VMMenu.DropDownItems, true); MW(MainWindowWrapper.VMMenu.HideDropDown); MW(MainWindowWrapper.StorageMenu.Select); MW(MainWindowWrapper.StorageMenu.ShowDropDown); Thread.Sleep(100); AssertToolStripItems(ixmoString, storageMenu, MainWindowWrapper.StorageMenu.DropDownItems, true); MW(MainWindowWrapper.StorageMenu.HideDropDown); MW(MainWindowWrapper.TemplatesMenu.Select); MW(MainWindowWrapper.TemplatesMenu.ShowDropDown); Thread.Sleep(100); AssertToolStripItems(ixmoString, templatesMenu, MainWindowWrapper.TemplatesMenu.DropDownItems, true); MW(MainWindowWrapper.TemplatesMenu.HideDropDown); } private static bool ToolStripItemsEqual(ExpectedMenuItem[] expectedItems, List itemsList) { if (expectedItems.Length != itemsList.Count) { return false; } for (int i = 0; i < expectedItems.Length; i++) { if (expectedItems[i] is ExpectedSeparator && itemsList[i] is ToolStripSeparator) { continue; } else if (expectedItems[i] is ExpectedSeparator && !(itemsList[i] is ToolStripSeparator)) { return false; } else if (!(expectedItems[i] is ExpectedSeparator) && itemsList[i] is ToolStripSeparator) { return false; } else if (((ExpectedTextMenuItem)expectedItems[i]).text != itemsList[i].Text.TrimEnd()) { return false; } } return true; } private void AssertToolStripItems(string ixmoString, ExpectedMenuItem[] expectedItems, ToolStripItemCollection items, bool checkMnemonics) { List itemsList = GetVisibleToolStripItems(items); // some menu items take time before they become their final value. MWWaitFor(() => ToolStripItemsEqual(expectedItems, itemsList)); Assert.AreEqual(expectedItems.Length, itemsList.Count, string.Format("Wrong number of items in the menu for {0}: {1} != {2}", ixmoString, GetNames(expectedItems), GetNames(itemsList))); List usedMnemonics = new List(); for (int i = 0; i < expectedItems.Length; ++i) { ToolStripItem item = itemsList[i]; if (expectedItems[i] is ExpectedSeparator) { Assert.IsTrue(item is ToolStripSeparator, "At position " + i + " for " + ixmoString + ", expected separator, found " + item.Text); } else { ToolStripMenuItem menuItem = item as ToolStripMenuItem; ExpectedTextMenuItem expected = expectedItems[i] as ExpectedTextMenuItem; Assert.AreEqual(expected.text, item.Text.TrimEnd(), "Wrong item at position " + i + " for " + ixmoString); Assert.AreEqual(expected.enabled, item.Enabled, "Wrong enablement for item " + item.Text + " at position " + i + " for " + ixmoString); if (checkMnemonics && item.Text.TrimEnd() != "(empty)" && !expected.skipMnemonicCheck) { char c = ExtractMnemonic(item.Text.TrimEnd()); if (usedMnemonics.Contains(c)) Assert.Fail(string.Format("Item '{0}' duplicates mnemnonic '{1}'", item.Text, c)); } if (menuItem != null && menuItem.DropDownItems.Count > 0 && menuItem.Enabled) { MW(menuItem.ShowDropDown); AssertToolStripItems(ixmoString, expected.DropDownItems, menuItem.DropDownItems, checkMnemonics); } if (expected.chcked.HasValue) { ToolStripButton buttonItem = item as ToolStripButton; if (menuItem != null) { Assert.AreEqual(expected.chcked.Value, menuItem.Checked, "Wrong checked state for item " + item.Text + " at position " + i + " for " + ixmoString); } else if (buttonItem != null) { Assert.AreEqual(expected.chcked.Value, buttonItem.Checked, "Wrong checked state for item " + item.Text + " at position " + i + " for " + ixmoString); } } } } } private char ExtractMnemonic(string p) { int mnemonicIndex = p.IndexOf('&'); if (mnemonicIndex == -1 || mnemonicIndex == p.Length - 1) Assert.Fail(string.Format("Menu item '{0}' is missing a mnemonic", p)); return p[mnemonicIndex + 1]; } protected static List GetVisibleToolStripItems(ToolStripItemCollection items) { return Util.PopulateList(items).FindAll(t => t.Available); } private string GetNames(ExpectedMenuItem[] items) { List l = new List(); foreach (ExpectedMenuItem i in items) { l.Add(i.ToString()); } return string.Join(", ", l.ToArray()); } private string GetNames(List items) { List l = new List(); foreach (ToolStripItem i in items) { l.Add(i.Text); } return string.Join(", ", l.ToArray()); } protected static bool IsMaster(Host host) { return host.IsMaster(); } protected static bool IsSlave(Host host) { return !host.IsMaster(); } protected static bool HasTools(VM vm) { return !vm.is_a_template && vm.IsRunning&& vm.virtualisation_status != VM.VirtualisationStatus.PV_DRIVERS_NOT_INSTALLED && vm.virtualisation_status != VM.VirtualisationStatus.PV_DRIVERS_OUT_OF_DATE; } protected static bool NoTools(VM vm) { return !vm.is_control_domain && !vm.is_a_template && vm.IsRunning && !HasTools(vm); } protected static bool IsShutdown(VM vm) { return !vm.is_a_template && vm.power_state == vm_power_state.Halted; } protected static bool IsDefaultTemplate(VM vm) { return vm.is_a_template && vm.DefaultTemplate && vm.name_label != "XenSource P2V Server"; } protected static bool CanDetach(SR sr) { return sr.IsDetachable() && !HelpersGUI.GetActionInProgress(sr); } protected static bool CanForget(SR sr) { return !sr.HasRunningVMs() && sr.CanCreateWithXenCenter && sr.allowed_operations.Contains(storage_operations.forget) && !HelpersGUI.GetActionInProgress(sr); } protected static bool CanDestroy(SR sr) { return !sr.HasRunningVMs() && sr.CanCreateWithXenCenter && sr.allowed_operations.Contains(storage_operations.destroy) && !HelpersGUI.GetActionInProgress(sr); } protected static bool CanSetAsDefault(SR sr) { return sr.HasPBDs && !SR.IsDefaultSr(sr) && sr.SupportsVdiCreate() && (sr.shared || sr.Connection.Cache.HostCount <= 1) && !HelpersGUI.GetActionInProgress(sr); } /// /// Adds the "Expand All" and "Collapse Children" expected items to the specified list for the specified node. /// /// The node. /// The expected items to be added to. protected void AddExpectedExpandAndCollapseItems(VirtualTreeNode node, List expectedItems) { bool expandAll = false; bool collapseChildren = false; MW(delegate { expandAll = new List(node.Descendants).Find(n => !n.IsExpanded) != null; collapseChildren = new List(node.Nodes).Find(n => n.Nodes.Count > 0 && n.IsExpanded) != null; }); if (expandAll) { expectedItems.Add(new ExpectedTextMenuItem("E&xpand All", true)); } if (collapseChildren) { expectedItems.Add(new ExpectedTextMenuItem("&Collapse Children", true)); } } protected void SetPluginCheckstate(CheckState state) { HandleModalDialog("Options", MainWindowWrapper.ToolsMenuItems.OptionsToolStripMenuItem.PerformClick, p => { var grid = TestUtils.GetFieldDeep(p.Item, "pluginOptionsPage1.m_gridPlugins"); foreach (DataGridViewRow row in grid.Rows) row.Cells[0].Value = (state == CheckState.Checked); p.OkButton.PerformClick(); }); } protected void EnableAllPlugins() { SetPluginCheckstate(CheckState.Checked); } protected void DisableAllPlugins() { SetPluginCheckstate(CheckState.Unchecked); } public class ExpectedMenuItem { } public class ExpectedSeparator : ExpectedMenuItem { public override string ToString() { return ""; } } public class ExpectedTextMenuItem : ExpectedMenuItem { public string text; public bool enabled; public bool? chcked; public ExpectedMenuItem[] DropDownItems; public bool skipMnemonicCheck = false; public ExpectedTextMenuItem(string text, bool enabled) : this(text, enabled, new ExpectedMenuItem[0]) { } public ExpectedTextMenuItem(string text, bool enabled, ExpectedMenuItem[] dropDownItems) { this.text = text; this.enabled = enabled; this.DropDownItems = dropDownItems; } public ExpectedTextMenuItem(string text, bool enabled, bool chcked, ExpectedMenuItem[] dropDownItems) : this(text, enabled, dropDownItems) { this.chcked = chcked; } public ExpectedTextMenuItem(string text, bool enabled, bool chcked) : this(text, enabled, chcked, new ExpectedMenuItem[0]) { } public ExpectedTextMenuItem(string text, bool enabled, bool chcked, bool skipMnemonicCheck) : this(text, enabled, chcked, new ExpectedMenuItem[0]) { this.skipMnemonicCheck = skipMnemonicCheck; } public override string ToString() { return enabled ? text : string.Format("{0} (disabled)", text); } } } }