Skip to content

Commit

Permalink
Add support for timeouts for attach applications
Browse files Browse the repository at this point in the history
Fixes #149
  • Loading branch information
Jani Mikkonen committed Aug 12, 2019
1 parent 0a66dc6 commit 06e4933
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 28 deletions.
4 changes: 4 additions & 0 deletions UIAutomationTest/delayed_start.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pushd %~dp0
ping 127.0.0.1 -n 6
start /B bin\Debug\UIAutomationTest.exe
popd
19 changes: 19 additions & 0 deletions atests/attach_application.robot
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,26 @@ Attach To A Running Application By Id
Attach Application By Id ${test application id}
Application Should Be Attached

Attach To A Running Application By Invalid Name
Run Keyword And Expect Error STARTS: Unable to locate application with identifier: ${INVALID TEST APPLICATION NAME}
... Attach Application By Name ${INVALID TEST APPLICATION NAME}

Attach To A Running Application By Invalid Name With Timeout
Run Keyword And Expect Error STARTS: Unable to locate application with identifier: ${INVALID TEST APPLICATION NAME}
... Attach Application By Name ${INVALID TEST APPLICATION NAME} timeout=20 seconds

Attach To Application With Timeout
[Setup] Delayed Start Test Application
[Timeout] 1 minute
[Teardown] Terminate Process delayed kill=true
Attach Application By Name ${TEST APPLICATION NAME} timeout=1 minute
Application Should Be Attached
Close Application

*** Keywords ***
Delayed Start Test Application
Start Process ${DELAYED TEST APPLICATION} alias=delayed stdout=${EXECDIR}${/}output${/}stdout.txt stderr=${EXECDIR}${/}output${/}stderr.txt

Start Test Application
${handle} = Start Process ${TEST APPLICATION}
Set Test Variable ${handle}
Expand Down
4 changes: 1 addition & 3 deletions atests/configuration.robot
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Library OperatingSystem
Library String
Library WhiteLibrary
Suite Setup None
Suite Teardown White Configuration Parameters Restore
Test Teardown White Configuration Parameters Restore

*** Test Cases ***
Set White Busy Timeout
Expand All @@ -29,11 +29,9 @@ Set White Drag Step Count
${WHITE_DRAG_STEP_COUNT} Get White Drag Step Count
Should Be Equal ${WHITE_DRAG_STEP_COUNT} ${3}


*** Keywords ***
White Configuration Parameters Restore
#These defaults are defined in White Stack source code.
Set White Busy Timeout 5000 ms
Set White Find Window Timeout 30000 ms
Set White Double Click Interval 0 ms

2 changes: 2 additions & 0 deletions atests/resource.robot
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Library WhiteLibrary

*** Variables ***
${TEST APPLICATION} ${EXECDIR}${/}UIAutomationTest${/}bin${/}Debug${/}UIAutomationTest.exe
${DELAYED TEST APPLICATION} ${EXECDIR}${/}UIAutomationTest${/}delayed_start.bat
${TEST APPLICATION NAME} UIAutomationTest
${INVALID TEST APPLICATION NAME} UIAutomationTestThatDoesNotExist
${TEST APPLICATION WINDOW TITLE} UI Automation Test Window
${TEST WHITE APPLICATION} ${EXECDIR}${/}WhiteTestApp${/}WpfTestApplication.exe
${TEST WHITE APPLICATION NAME} MainWindow
Expand Down
43 changes: 38 additions & 5 deletions src/WhiteLibrary/keywords/application.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from robot.api import logger # noqa: F401 #pylint: disable=unused-import
from robot.utils import timestr_to_secs
from System.Diagnostics import ProcessStartInfo
from WhiteLibrary.keywords.librarycomponent import LibraryComponent
from WhiteLibrary.keywords.robotlibcore import keyword
from TestStack.White import Application
from WhiteLibrary.utils.wait import Wait
from TestStack.White import Application, WhiteException


class ApplicationKeywords(LibraryComponent):
Expand All @@ -26,27 +28,58 @@ def launch_application(self, sut_path, args=None):
else:
self.state.app = Application.Launch(sut_path)

@staticmethod
def _attach_application(sut_identifier, timeout=0):
exception_message = "Unable to locate application with identifier: {}".format(sut_identifier)
if timeout == 0:
try:
return Application.Attach(sut_identifier)
except WhiteException:
raise AssertionError(exception_message)

# using hack due to 2.7 doesnt support nonlocal keyword
# and inner function cant modify primitive datatypes.
# aand im trying to avoid calling Application.Attach()
# multiple times as it allocates memory on python .net
# side.

hack = {"sut": None}

def search_application():
try:
hack["sut"] = Application.Attach(sut_identifier) # noqa: F841
return True
except WhiteException:
return False

Wait.until_true(search_application, timeout, exception_message)

return hack["sut"]

@keyword
def attach_application_by_name(self, sut_name):
def attach_application_by_name(self, sut_name, timeout=0):
"""Attaches a running application by name.
``sut_name`` is the name of the process.
``timeout`` is the maximum time to wait as a Robot time string. (Optional)
Example:
| Attach Application By Name | UIAutomationTest |
"""
self.state.app = Application.Attach(sut_name)
self.state.app = self._attach_application(sut_name, timeout)

@keyword
def attach_application_by_id(self, sut_id):
def attach_application_by_id(self, sut_id, timeout=0):
"""Attaches a running application by process id.
``sut_id`` is the application process id.
``timeout`` is the maximum time to wait as a Robot time string. (Optional)
Example:
| Attach Application By Id | 12188 |
"""
self.state.app = Application.Attach(int(sut_id))
self.state.app = self._attach_application(int(sut_id), timeout)

@keyword
def close_application(self):
Expand Down
29 changes: 9 additions & 20 deletions src/WhiteLibrary/keywords/items/uiitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from WhiteLibrary.keywords.librarycomponent import LibraryComponent
from WhiteLibrary.keywords.robotlibcore import keyword
from WhiteLibrary.utils.click import Clicks
import time
from WhiteLibrary.utils.wait import Wait


class UiItemKeywords(LibraryComponent):
Expand Down Expand Up @@ -98,10 +98,10 @@ def wait_until_item_exists(self, locator, timeout):
See `Waiting and timeouts` for more information about waiting in WhiteLibrary.
"""
self._wait_until_true(lambda: self._item_exists(locator),
timeout,
u"Item with locator '{}' did not exist within {} seconds"
.format(locator, timestr_to_secs(timeout)))
Wait.until_true(lambda: self._item_exists(locator),
timeout,
u"Item with locator '{}' did not exist within {} seconds"
.format(locator, timestr_to_secs(timeout)))

@keyword
def wait_until_item_does_not_exist(self, locator, timeout):
Expand All @@ -116,22 +116,11 @@ def wait_until_item_does_not_exist(self, locator, timeout):
See `Waiting and timeouts` for more information about waiting in WhiteLibrary.
"""
self._wait_until_true(lambda: not self._item_exists(locator),
timeout,
u"Item with locator '{}' still existed after {} seconds"
.format(locator, timestr_to_secs(timeout)))
Wait.until_true(lambda: not self._item_exists(locator),
timeout,
u"Item with locator '{}' still existed after {} seconds"
.format(locator, timestr_to_secs(timeout)))

def _item_exists(self, locator):
search_criteria = self.state._get_search_criteria(locator)
return self.state.window.Exists(search_criteria)

@staticmethod
def _wait_until_true(condition, timeout, error_msg):
timeout = timestr_to_secs(timeout)
max_wait = time.time() + timeout
while True:
if condition():
break
if time.time() > max_wait:
raise AssertionError(error_msg)
time.sleep(0.1)
16 changes: 16 additions & 0 deletions src/WhiteLibrary/utils/wait.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import time
from robot.utils import timestr_to_secs


class Wait:
@staticmethod
def until_true(condition, timeout, error_msg):
"""Helper to wait until given condition is met."""
timeout = timestr_to_secs(timeout)
max_wait = time.time() + timeout
while True:
if condition():
break
if time.time() > max_wait:
raise AssertionError(error_msg)
time.sleep(0.1)

0 comments on commit 06e4933

Please sign in to comment.