Регулярный запуск интерактивного процесса (тесты WatiN) через планировщик заданий

Я использую набор тестов WatiN, управляющих IE, чтобы периодически проверять работоспособность с целью мониторинга сайта.

Пакет работает нормально, когда я вызываю его в интерактивном режиме и / или когда я настраиваю задачу в планировщике задач на «Запускать только тогда, когда пользователь вошел в систему».

Однако, когда я устанавливаю его на «Запускать независимо от того, вошел ли пользователь в систему или нет» и проверяю опцию «Запускать с наивысшими привилегиями» (WatiN не может нормально взаимодействовать с браузером под Windows Server 2008 и многих других ОС без администратора привилегии), WatiN не может удовлетворительно взаимодействовать с его экземплярами iexplore.exe (они запускаются, но я получаю исключение тайм-аута, как описано в этом сообщении). Я добавил сайт, на который я обращаюсь, в список надежных сайтов как для административного, так и для неадминистративного контекста IE. Я пробовал с повышением прав и без него, с отключением ESC и без него, а также с отключением и без отключения защищенного режима для зоны Интернета. Поскольку мои тесты, не связанные с графическим интерфейсом пользователя, устраивают, я предполагаю, что это ограничение типа интерактивности, которое возможно в контексте неинтерактивной запланированной задачи, даже если «Запускать с наивысшими привилегиями».

Прямо сейчас мой временный обходной путь состоит в том, чтобы требовать, чтобы сеанс [TS] всегда оставался открытым, готовым к запуску запланированной задачи.

Если бы я настаивал на этом, я бы как минимум добавил уведомление о пульсе, чтобы позволить чему-либо отслеживать, что задача действительно запускается [например, если кто-то выйдет из сеанса или перезагрузит компьютер].

Однако я ищу что-то более постоянное - что-то, что способно регулярно вызывать мои тесты WatiN [запускать с использованием xunit-console.x86.exe v 1.5] в моем окне Windows Server 2008 [x64], точно так же, как планировщик задач, но с правильным интерактивным сеансом.

Я бы предпочел не использовать psexec или remcom, если это возможно, и не вижу, как создание службы Windows может сделать что-либо, кроме добавления еще одной точки отказа, но мне было бы интересно услышать обо всех проверенных решениях.


person Ruben Bartelink    schedule 30.09.2009    source источник


Ответы (2)


Мне удалось запустить тесты Watin с помощью запланированной задачи в режиме «Запускать независимо от того, вошел ли пользователь в систему или нет». В моем случае я отследил проблему до того, что m_Proc.MainWindowHandle всегда был равен 0, когда IE создается из запланированной задачи, запущенной без вошедшего в систему пользователя. В источниках Watin это функция IE.cs: CreateIEParhibitedInitializedInNewProcess.

Мой обходной путь - вручную перечислить окна верхнего уровня и найти окно с 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);
        }
    }

тогда вместо нового IE () используйте IEBrowserHelper.CreateIEBrowser ()

person shurik    schedule 06.03.2012
comment
Интересный. На каких операционках работает? Лично у меня больше нет этого требования, поэтому мне неудобно даже думать об этом как о решении, так что это долгий путь принятия. Я не могу представить себе зависимость от чего-либо этого хакерского IRL, но если не торопиться, вот +1 - person Ruben Bartelink; 06.03.2012
comment
У меня есть это требование, я начал копать, и после того, как ничего из того, что я искал в Google, не сработало, пришлось погрузиться глубже и отладить Watin. Теперь это определенно работает для меня, и единственное изменение кода, которое я сделал, описано выше. Я не совсем понимаю, почему MainWindowHandle не работал, я также много играл с IE и настройками задач, но я думаю, что вернул все обратно, и он все еще работает. В любом случае спасибо за +1 :) мой первый пост и первый +1 здесь. - person shurik; 06.03.2012
comment
Отличное решение. Работает на Windows Server 2008 R2 и Windows 7 - person Diego; 16.04.2012
comment
Можно ли как-то изменить это, чтобы оно также работало для нескольких окон при выполнении стресс-тестов? - person Johny Skovdal; 06.05.2013

Из командной строки вы можете запланировать интерактивную задачу следующим образом:

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

... где sc - расписание, st - время начала, tn - выбранное вами имя задачи (может быть любым), а tr - команда, которую вы хотите запустить. Очевидно, что для повторяющейся задачи вы должны изменить sc на ежемесячный, еженедельный и т. Д. Просто введите "schtasks / create /?" для получения дополнительной информации.

person WEFX    schedule 05.01.2012
comment
Как вы думаете, почему это соответствует такому же планировщику задач, но с соответствующей оговоркой об интерактивном сеансе в вопросе? Вся проблема в том, что процесс должен быть интерактивным - использовали ли вы эту технику, чтобы сделать что-то похожее по своей природе. ... или я что-то упускаю? - person Ruben Bartelink; 06.01.2012
comment
Эта строка в моем ответе запускает интерактивную командную строку в сеансе консоли / администратора компьютера, но cmd.exe можно заменить другим исполняемым файлом. Возможно, я неправильно понял ваш вопрос. - person WEFX; 06.01.2012
comment
Если для пользователя A и B открыто 2 сеанса TS, как вы считаете, ваша команда выбирает, какой сеанс запускать / можно ли сделать так, чтобы она выбрала один вне, например. WinXP, где есть только одна сессия. AIUI Мне нужно, чтобы процесс был сгенерирован в интерактивном сеансе, то есть на реальном рабочем столе с настоящим пользовательским интерфейсом. то есть cmd.exe должен быть родительским для процесса в сеансе, вошедшем в систему, а не только неинтерактивной WindowStation. Честно говоря, я выгрузил большую часть этого контекста с тех пор, как был задан вопрос, и я знаю, что ужасно искажаю терминологию в этих комментариях! - person Ruben Bartelink; 06.01.2012