Enforce failure if MWWaitFor times out without a message, ortherwise failures

are swallowed. Use optional parameters instead of method overloads. Some other
modernisations.

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
This commit is contained in:
Konstantina Chremmou 2019-01-12 18:14:57 +00:00 committed by Mihaela Stoica
parent 1bf47e47df
commit 58b65f8a8a
5 changed files with 84 additions and 300 deletions

View File

@ -121,33 +121,24 @@ namespace XenAdmin.Core
}
}
/// <summary>
/// Gets the first window that has the specified window text.
/// </summary>
/// <param name="text">The text that the window must have.</param>
/// <returns>The first window that has the specified window text.</returns>
public static Win32Window GetWindowWithText(string text)
{
return GetWindowWithText(text, w => true);
}
/// <summary>
/// Gets the first window that has the specified window text and matches the specified Predicate.
/// </summary>
/// <param name="text">The text that the window must have.</param>
/// <param name="match">The Predicate that the window must match.</param>
/// <returns>The first window that has the specified window text and matches the specified Predicate.</returns>
public static Win32Window GetWindowWithText(string text, Predicate<Win32Window> match)
public static Win32Window GetWindowWithText(string text, Predicate<Win32Window> match = null)
{
Util.ThrowIfParameterNull(match, "match");
if (match == null)
match = w => true;
Thread.Sleep(100);
foreach (Win32Window window in TopLevelWindows)
{
if (window.Text == text && match(window))
{
return window;
}
}
return null;
}

View File

@ -88,68 +88,59 @@ namespace XenAdminTests
/// <summary>
/// Waits for the specified action to return true. The action is run on the main program thread.
/// The action is attempted 300 times, with a 100ms wait between tries. If the action doesn't
/// succeed after being retried then the calling test is failed with the specified message.
/// If assert message is null, then the test won't be failed.
/// The action is attempted 300 times, with a 100ms wait between tries.
/// If the action has not succeeeded after the retires, the calling test fails with the specified message.
/// </summary>
/// <param name="action">The action.</param>
/// <param name="assertMessage">The assert message.</param>
/// <returns>A value indicating whether the action was successful.</returns>
protected bool MWWaitFor(Func<bool> action, string assertMessage)
protected bool MWWaitFor(Func<bool> action, string assertMessage = null)
{
bool success = false;
for (int i = 0; i < 500 && !success; i++)
for (int i = 0; i < 500; i++)
{
success = MW<bool>(action);
if (!success)
{
Thread.Sleep(300);
}
success = MW(action);
if (success)
break;
Thread.Sleep(300);
}
if (assertMessage != null && !success)
{
Assert.Fail(assertMessage);
}
if (!success)
Assert.Fail(string.IsNullOrEmpty(assertMessage) ? "Waited unsuccessfully" : assertMessage);
return success;
}
/// <summary>
/// Waits for the specified action to return true. The action is run on the calling thread.
/// The action is attempted 300 times, with a 100ms wait between tries. If the action doesn't
/// succeed after being retried then the calling test is failed with the specified message.
/// If assert message is null, then the test won't be failed.
/// The action is attempted 300 times, with a 100ms wait between tries.
/// If the action has not succeeded after the retries, the calling test fails with the specified message.
/// </summary>
/// <param name="action">The action.</param>
/// <param name="assertMessage">The assert message.</param>
/// <returns>A value indicating whether the action was successful.</returns>
protected bool WaitFor(Func<bool> action, string assertMessage)
protected void WaitFor(Func<bool> action, string assertMessage = null)
{
bool success = false;
for (int i = 0; i < 300 && !success; i++)
for (int i = 0; i < 300; i++)
{
success = action();
if (!success)
{
Thread.Sleep(100);
}
if (success)
break;
Thread.Sleep(100);
}
if (assertMessage != null && !success)
{
Assert.Fail(assertMessage);
}
return success;
if (!success)
Assert.Fail(string.IsNullOrEmpty(assertMessage) ? "Waited unsuccessfully" : assertMessage);
}
internal Win32Window WaitForWindowToAppear(string windowText)
internal Win32Window WaitForWindowToAppear(string windowText, Predicate<Win32Window> match = null)
{
return WaitForWindowToAppear(windowText, w => true);
}
if (match == null)
match = w => true;
internal Win32Window WaitForWindowToAppear(string windowText, Predicate<Win32Window> match)
{
Win32Window window = null;
Func<bool> func = delegate
{
@ -157,30 +148,10 @@ namespace XenAdminTests
return window != null;
};
WaitFor(func, "Window with text " + windowText + " didn't appear.");
WaitFor(func, $"Window with text {windowText} didn't appear.");
return window;
}
/// <summary>
/// Waits for the specified action to return true. The action is run on the main program thread.
/// The action is attempted 200 times, with a 100ms wait between tries.
/// </summary>
/// <returns>A value indicating whether the action was successful.</returns>
protected bool MWWaitFor(Func<bool> action)
{
return MWWaitFor(action, null);
}
/// <summary>
/// Waits for the specified action to return true. The action is run on the calling thread.
/// The action is attempted 200 times, with a 100ms wait between tries.
/// </summary>
/// <returns>A value indicating whether the action was successful.</returns>
protected bool WaitFor(Func<bool> action)
{
return WaitFor(action, null);
}
/// <summary>
/// <see cref="Application.DoEvents()"/> doesn't seems to work from the test framework. This is a replacement.
/// </summary>
@ -507,7 +478,7 @@ namespace XenAdminTests
});
MW(openDialog);
MWWaitFor(() => closed, "Dialog \"" + windowText + "\" was not closed.");
MWWaitFor(() => closed, $"Dialog {windowText} was not closed.");
}
/// <summary>

View File

@ -29,16 +29,11 @@
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using XenAdmin;
using System.Windows.Forms;
using XenAdmin.Controls;
using XenAdmin.Controls.MainWindowControls;
using XenAdmin.Controls.XenSearch;
using XenAdmin.Plugins;
using XenAdmin.Commands;
namespace XenAdminTests
{
@ -49,193 +44,48 @@ namespace XenAdminTests
{
}
public ToolStripMenuItem ToolsMenu
{
get
{
return GetField<ToolStripMenuItem>("toolsToolStripMenuItem");
}
}
public ToolStripMenuItem ToolsMenu => GetField<ToolStripMenuItem>("toolsToolStripMenuItem");
public ToolsMenuWrapper ToolsMenuItems
{
get
{
return new ToolsMenuWrapper(Item);
}
}
public ToolsMenuWrapper ToolsMenuItems => new ToolsMenuWrapper(Item);
public ToolStripMenuItem WindowMenu
{
get
{
return GetField<ToolStripMenuItem>("windowToolStripMenuItem");
}
}
public ToolStripMenuItem HelpMenu => GetField<ToolStripMenuItem>("helpToolStripMenuItem");
public ToolStripMenuItem HelpMenu
{
get
{
return GetField<ToolStripMenuItem>("helpToolStripMenuItem");
}
}
public ToolStripMenuItem ViewMenu => GetField<ToolStripMenuItem>("viewToolStripMenuItem");
public ToolStripMenuItem ViewMenu
{
get
{
return GetField<ToolStripMenuItem>("viewToolStripMenuItem");
}
}
public ToolStripMenuItem FileMenu => GetField<ToolStripMenuItem>("fileToolStripMenuItem");
public ToolStripMenuItem PoolMenu => GetField<ToolStripMenuItem>("poolToolStripMenuItem");
public ToolStripMenuItem FileMenu
{
get
{
return GetField<ToolStripMenuItem>("fileToolStripMenuItem");
}
}
public ToolStripMenuItem VMMenu => GetField<ToolStripMenuItem>("VMToolStripMenuItem");
public ToolStripMenuItem PoolMenu
{
get
{
return GetField<ToolStripMenuItem>("poolToolStripMenuItem");
}
}
public ToolStripMenuItem TemplatesMenu => GetField<ToolStripMenuItem>("templatesToolStripMenuItem");
public ToolStripMenuItem VMMenu
{
get
{
return GetField<ToolStripMenuItem>("VMToolStripMenuItem");
}
}
public ToolStripEx MainToolStrip => GetField<ToolStripEx>("ToolStrip");
public ToolStripMenuItem TemplatesMenu
{
get
{
return GetField<ToolStripMenuItem>("templatesToolStripMenuItem");
}
}
public MainToolBarWrapper MainToolStripItems => new MainToolBarWrapper(Item);
public ToolStripEx MainToolStrip
{
get
{
return GetField<ToolStripEx>("ToolStrip");
}
}
public PluginManager PluginManager => GetField<PluginManager>("pluginManager");
public MainToolBarWrapper MainToolStripItems
{
get
{
return new MainToolBarWrapper(Item);
}
}
public FlickerFreeTreeView TreeView => TestUtils.GetFlickerFreeTreeView(Item, "navigationPane.navigationView.treeView");
public PluginManager PluginManager
{
get
{
return GetField<PluginManager>("pluginManager");
}
}
public ToolStripMenuItem StorageMenu => Item.StorageToolStripMenuItem;
public FlickerFreeTreeView TreeView
{
get { return TestUtils.GetFlickerFreeTreeView(Item, "navigationPane.navigationView.treeView"); } }
public StorageMenuWrapper StorageMenuItems => new StorageMenuWrapper(Item);
public CommandToolStripMenuItem AddHostToolStripMenuItemInPoolMenu
{
get
{
return GetField<CommandToolStripMenuItem>("addServerToolStripMenuItem");
}
}
public ToolStripMenuItem HostMenu => GetField<ToolStripMenuItem>("HostMenuItem");
public ToolStripMenuItem StorageMenu
{
get
{
return Item.StorageToolStripMenuItem;
}
}
public VMMenuWrapper VMMenuItems => new VMMenuWrapper(Item);
public StorageMenuWrapper StorageMenuItems
{
get
{
return new StorageMenuWrapper(Item);
}
}
public ViewMenuWrapper ViewMenuItems => new ViewMenuWrapper(Item);
public ToolStripMenuItem HostMenu
{
get
{
return GetField<ToolStripMenuItem>("HostMenuItem");
}
}
public TabControl TheTabControl => Item.TheTabControl;
public HostMenuWrapper HostMenuItems
{
get
{
return new HostMenuWrapper(Item);
}
}
public MenuStripEx MainMenuBar => GetField<MenuStripEx>("MainMenuBar");
public VMMenuWrapper VMMenuItems
{
get
{
return new VMMenuWrapper(Item);
}
}
public NetworkTabPageWrapper NetworkPage => new NetworkTabPageWrapper(Item.NetworkPage);
public ViewMenuWrapper ViewMenuItems
{
get
{
return new ViewMenuWrapper(Item);
}
}
public TabPage TabPageNetwork => GetField<TabPage>("TabPageNetwork");
public TabControl TheTabControl
{
get
{
return Item.TheTabControl;
}
}
public MenuStripEx MainMenuBar
{
get
{
return GetField<XenAdmin.Controls.MenuStripEx>("MainMenuBar");
}
}
public NetworkTabPageWrapper NetworkPage
{
get
{
return new NetworkTabPageWrapper(Item.NetworkPage);
}
}
public TabPage TabPageNetwork
{
get
{
return GetField<TabPage>("TabPageNetwork");
}
}
public Form[] OwnedForms => Item.OwnedForms;
}
}

View File

@ -30,12 +30,10 @@
*/
using System;
using System.Data;
using System.Reflection;
using System.Windows.Forms;
using NUnit.Framework;
using XenAdmin;
using XenAdmin.Core;
namespace XenAdminTests
{
@ -50,44 +48,25 @@ namespace XenAdminTests
{
private readonly TClass _item;
/// <summary>
/// Initializes a new instance of the <see cref="TestWrapper&lt;TClass&gt;"/> class.
/// </summary>
/// <param name="item">The class that is to be wrapped.</param>
public TestWrapper(TClass item)
protected TestWrapper(TClass item)
{
Util.ThrowIfParameterNull(item, "item");
_item = item;
}
private static TClass GetControlFromWindow(IWin32Window window)
{
Control control = Control.FromHandle(window.Handle);
if (!(control is TClass))
{
throw new ArgumentException("window is not a " + typeof(TClass).Name, "window");
}
return control as TClass;
}
/// <summary>
/// Initializes a new instance of <see cref="TestWrapper&lt;TClass&gt;"/> class.
/// </summary>
/// <param name="window">The window.</param>
public TestWrapper(IWin32Window window)
protected TestWrapper(IWin32Window window)
: this(GetControlFromWindow(window))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TestWrapper&lt;TClass&gt;"/> class.
/// </summary>
/// <param name="windowText">The window text of the window being wrapped.</param>
public TestWrapper(string windowText)
: this(Win32Window.GetWindowWithText(windowText, w => Control.FromHandle(w.Handle) is TClass))
private static TClass GetControlFromWindow(IWin32Window window)
{
var control = Control.FromHandle(window.Handle) as TClass;
if (control == null)
throw new ArgumentException($"window is not a {typeof(TClass).Name} window");
return control;
}
/// <summary>
@ -112,10 +91,10 @@ namespace XenAdminTests
}
/// <summary>
/// Gets the value of the private field from the wrapped classes *base* class of the specified name.
/// Gets the value of a given private field from the wrapped class's *base* class
/// </summary>
/// <typeparam name="TField">The type of the field.</typeparam>
/// <param name="name">The name of the private field.</param>
/// <param name="name">The name of the field.</param>
/// <returns>The value of the private field from the base class of the wrapped class of the specified name.</returns>
protected TField GetBaseClassField<TField>(string name)
{
@ -125,14 +104,13 @@ namespace XenAdminTests
{
Type baseType = _item.GetType().BaseType;
if(baseType == null)
throw new NoNullAllowedException("Base class type was null, check the class has a base class");
Assert.NotNull(baseType, $"{name} is a field of a class that has no base class");
return (TField)baseType.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_item);
}
catch (Exception e)
{
Assert.Fail(string.Format("Field {0} of {1} throws {2}.", name, typeof(TClass).Name, e.GetType().Name));
Assert.Fail($"Field {name} of {typeof(TClass).Name} throws {e.GetType().Name}.");
throw;
}
}

View File

@ -118,37 +118,21 @@ namespace XenAdminTests.MiscTests
[Test]
public void TestMultipleUrisWithNoneValid()
{
Uri uri1 = new Uri("http://fgdfffgd.dfgdfgd.dfg");
Uri uri2 = new Uri("http://fgdfgd.dfgdfgd.dfg");
Uri navCancelUri = new Uri("res://ieframe.dll/navcancl.htm#http://fgdfgd.dfgdfgd.dfg/");
Uri curUri = null;
bool navigating = false;
bool navigated = false;
bool navError = false;
_wb.Navigating += (s, e) =>
{
if (e.Url != navCancelUri)
{
Assert.IsFalse(navigating);
}
else
{
Assert.IsTrue(navigating);
}
navigating = true;
if (e.Url == curUri)
navigating = true;
};
_wb.Navigated += (s, e) =>
{
if (e.Url != navCancelUri)
{
Assert.IsFalse(navigated);
}
else
{
Assert.IsTrue(navigated);
}
navigated = true;
if (e.Url == curUri)
navigated = true;
};
_wb.NavigateError += (s, e) =>
@ -157,10 +141,20 @@ namespace XenAdminTests.MiscTests
navError = true;
};
var uris = new[] { uri1, uri2 };
//Use non-existing URLs with existing rather than completely fictional
//domains, otherwise the NavigationError even is not fired
var uris = new[]
{
new Uri("http://127.0.0.1/blah"),
new Uri("http://127.0.0.1/blahblah")
};
foreach (var uri in uris)
{
var curUri = uri;
curUri = uri;
navigated = navigated = navError = false;
MW(() => _wb.Navigate(curUri));
MWWaitFor(() => navigating && navigated && navError, "Navigation didn't take place.");
}