通过任务计划程序定期调用交互式进程(WatiN 测试)

发布于 2024-08-06 09:30:56 字数 898 浏览 4 评论 0原文

我正在使用一套 WatiN 测试驱动 IE 进行一些定期健全性检查,以监控站点。

当我以交互方式调用它和/或当我在任务计划程序中将任务配置为“仅在用户登录时运行”时,该套件工作正常。

但是,当我将其设置为“无论用户是否登录都运行”,并选中“以最高权限运行”选项时(在没有管理员权限的情况下,WatiN 无法在 Windows Server 2008 和许多其他操作系统下与浏览器令人满意地对话)权限),WatiN 无法与其 iexplore.exe 实例进行令人满意的通信(它们启动,但我得到一个 超时异常,详见本文)。我已将我正在访问的站点添加到 IE 管理和非管理上下文的受信任站点中。我尝试过使用和不使用提升功能、使用和不禁用 ESC 以及使用和使用和不关闭 Internet 区域的保护模式。由于我的非 GUI 测试很满意,我认为这是在非交互式计划任务上下文中可能的交互类型的限制,即使是在“以最高权限运行”时也是如此。

现在,我的临时解决方法是要求 [TS] 会话始终保持打开状态,准备运行计划任务。

如果我坚持这样做,我至少会添加一个心跳通知,以允许某些东西监视任务实际上正在运行[例如,如果有人注销会话或重新启动盒子]。

然而,我正在寻找更持久的东西 - 能够在我的 Windows Server 2008 [x64] 机器上定期调用我的 WatiN 测试 [使用 xunit-console.x86.exe v 1.5 运行] 的东西,就像任务计划程序一样,但是通过适当的交互式会话。

如果可能的话,我不想使用 psexec 或 remcom,并且不知道创建 Windows 服务除了添加另一个故障点之外还有什么作用,但我有兴趣了解所有经过验证的解决方案。

I'm using a suite of WatiN tests driving IE to do some periodic sanity checking for the purposes of monitoring a site.

The suite works fine when I invoke it interactively and/or when I configure the task in Task Scheduler to "Run only when the user is logged on".

However, when I set it to "Run whether the user is logged on or not", and check the "Run with highest privileges" option (WatiN can't talk to the browser satisfactorily under Windows Server 2008 and many other OSes without having admin privileges), WatiN can't communicate with it's iexplore.exe instances satisfactorily (they start, but I get a timeout exception as detailed in this post). I have added the site I'm hitting to the Trusted sites for both admin and non-admin contexts of IE. I've tried with and without elevation, with and without disabling ESC and with and with and without turning off Protected Mode for the internet zone. As my non-GUI tests are happy, I assume it's a limitation of the type of interactivity that's possible in the context of a non-interactive Scheduled Task, even when "Run with highest privileges".

Right now, my temporary workaround is to require a [TS] session to remain open at all times, ready to run the scheduled task.

If I was to persist with this, I'd at a minimum add a heartbeat notification to allow something to monitor that the task is actually getting to run [e.g., if someone logs the session off or reboots the box].

However, I'm looking for something more permanent -- something that is capable of regularly invoking my WatiN tests [run using xunit-console.x86.exe v 1.5] on my Windows Server 2008 [x64] box, just like Task Scheduler but with a proper Interactive session.

I'd prefer not to use psexec or remcom if possible, and can't see how creating a Windows Service would do anything other than add another point of failure but I'd be interested to hear of all proven solutions out there.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

狼亦尘 2024-08-13 09:30:56

我能够在“无论用户是否登录都运行”模式下使用计划任务运行 Watin 测试。
就我而言,当从没有登录用户的情况下运行的计划任务创建 IE 时,我跟踪问题到 m_Proc.MainWindowHandle 始终为 0。
在 Watin 源代码中,这是在 IE.cs:CreateIEPartiallyInitializedInNewProcess 函数中。

我的解决方法是手动枚举顶级窗口并查找属于该进程的 className == "IEFrame" 的窗口,而不是使用 Process.MainWindowHandle 属性。

这是代码片段。所有 pinvoke 都是我直接从 Watin 源复制的。

   public static class IEBrowserHelper
    {
        private static Process CreateIExploreInNewProcess()
        {
            var arguments = "about:blank";

            arguments = "-noframemerging " + arguments;

            var m_Proc = Process.Start("IExplore.exe", arguments);
            if (m_Proc == null) throw new WatiN.Core.Exceptions.WatiNException("Could not start IExplore.exe process");

            return m_Proc;
        }
        class IeWindowFinder
        {
            #region Interop
            [DllImport("user32.dll", SetLastError = true)]
            static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
            public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
            [DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int GetClassName(IntPtr handleToWindow, StringBuilder className, int maxClassNameLength);
            #endregion

            readonly Process IeProcess;
            IntPtr HWnd = IntPtr.Zero;

            public IeWindowFinder(Process ieProcess)
            {
                this.IeProcess = ieProcess;
            }
            public IntPtr Find()
            {
                EnumWindows(FindIeWindowCallback, IntPtr.Zero);
                return HWnd;
            }

            bool FindIeWindowCallback(IntPtr hWnd, IntPtr lParam)
            {
                uint processId;
                GetWindowThreadProcessId(hWnd, out processId);
                if (processId == IeProcess.Id)
                {
                    int maxCapacity = 255;
                    var sbClassName = new StringBuilder(maxCapacity);
                    var lRes = GetClassName(hWnd, sbClassName, maxCapacity);
                    string className = lRes == 0 ? String.Empty : sbClassName.ToString();
                    if (className == "IEFrame")
                    {
                        this.HWnd = hWnd;
                        return false;
                    }
                }
                return true;
            }
        }

        public static WatiN.Core.IE CreateIEBrowser()
        {
            Process ieProcess = CreateIExploreInNewProcess();

            IeWindowFinder findWindow = new IeWindowFinder(ieProcess);

            var action = new WatiN.Core.UtilityClasses.TryFuncUntilTimeOut(TimeSpan.FromSeconds(WatiN.Core.Settings.AttachToBrowserTimeOut))
            {
                SleepTime = TimeSpan.FromMilliseconds(500)
            };

            IntPtr hWnd = action.Try(() =>
            {
                return findWindow.Find();
            });
            ieProcess.Refresh();
            return  WatiN.Core.IE.AttachTo<WatiN.Core.IE>(
                new WatiN.Core.Constraints.AttributeConstraint("hwnd", hWnd.ToString()), 5);
        }
    }

然后使用 IEBrowserHelper.CreateIEBrowser() 代替 new IE()

I was able to run Watin tests using Scheduled Task in the "Run whether user is logged on or not" mode.
In my case I tracked the issue down to m_Proc.MainWindowHandle being always 0 when IE is created from a scheduled task running without a logged on user.
In Watin sources this is in the IE.cs:CreateIEPartiallyInitializedInNewProcess function

My workaround is to manually enumerate top level windows and find a window with className == "IEFrame" that belongs to the process instead of using Process.MainWindowHandle property.

Here is the code snippet. All pinvoke i copied directly from Watin source.

   public static class IEBrowserHelper
    {
        private static Process CreateIExploreInNewProcess()
        {
            var arguments = "about:blank";

            arguments = "-noframemerging " + arguments;

            var m_Proc = Process.Start("IExplore.exe", arguments);
            if (m_Proc == null) throw new WatiN.Core.Exceptions.WatiNException("Could not start IExplore.exe process");

            return m_Proc;
        }
        class IeWindowFinder
        {
            #region Interop
            [DllImport("user32.dll", SetLastError = true)]
            static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
            public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
            [DllImport("user32.dll", SetLastError = true)]
            public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
            [DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
            internal static extern int GetClassName(IntPtr handleToWindow, StringBuilder className, int maxClassNameLength);
            #endregion

            readonly Process IeProcess;
            IntPtr HWnd = IntPtr.Zero;

            public IeWindowFinder(Process ieProcess)
            {
                this.IeProcess = ieProcess;
            }
            public IntPtr Find()
            {
                EnumWindows(FindIeWindowCallback, IntPtr.Zero);
                return HWnd;
            }

            bool FindIeWindowCallback(IntPtr hWnd, IntPtr lParam)
            {
                uint processId;
                GetWindowThreadProcessId(hWnd, out processId);
                if (processId == IeProcess.Id)
                {
                    int maxCapacity = 255;
                    var sbClassName = new StringBuilder(maxCapacity);
                    var lRes = GetClassName(hWnd, sbClassName, maxCapacity);
                    string className = lRes == 0 ? String.Empty : sbClassName.ToString();
                    if (className == "IEFrame")
                    {
                        this.HWnd = hWnd;
                        return false;
                    }
                }
                return true;
            }
        }

        public static WatiN.Core.IE CreateIEBrowser()
        {
            Process ieProcess = CreateIExploreInNewProcess();

            IeWindowFinder findWindow = new IeWindowFinder(ieProcess);

            var action = new WatiN.Core.UtilityClasses.TryFuncUntilTimeOut(TimeSpan.FromSeconds(WatiN.Core.Settings.AttachToBrowserTimeOut))
            {
                SleepTime = TimeSpan.FromMilliseconds(500)
            };

            IntPtr hWnd = action.Try(() =>
            {
                return findWindow.Find();
            });
            ieProcess.Refresh();
            return  WatiN.Core.IE.AttachTo<WatiN.Core.IE>(
                new WatiN.Core.Constraints.AttributeConstraint("hwnd", hWnd.ToString()), 5);
        }
    }

then instead of new IE() use IEBrowserHelper.CreateIEBrowser()

静若繁花 2024-08-13 09:30:56

从命令提示符中,您可以像这样安排交互式任务:

C:\Users\someUser>schtasks /create /sc once /st 16:28 /tn someTask /tr cmd.exe

... 其中 sc 是计划,st 是开始时间,tn 是您选择的任务名称(可以是任何名称),tr 是您想要的命令运行。显然,对于重复任务,您可以将 sc 更改为每月、每周等。只需输入“schtasks /create /?”了解更多信息。

From the command-prompt, you can schedule an interactive task like this:

C:\Users\someUser>schtasks /create /sc once /st 16:28 /tn someTask /tr cmd.exe

... where sc is the schedule, st is the start-time, tn is the taskname you choose (can be anything), and tr is the command you want to run. Obviously, for a recurring task, you would change sc to monthly, weekly, etc. Just type "schtasks /create /?" for more info.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文