2 1. [Introduce Aurum](#introduce-aurum)
3 2. [Command List](#command-list)
4 3. [Running on TV](#running-on-tv)
5 4. [Reference and Tip](#reference-and-tip)
8 - Aurum is a UI automation framework without UI Toolkit dependency.
10 Provides Commands to interact with the device UI by simulation user actions and introspection of the screen content.
12 It relies on the platform accessibility APIs to introspect the screen.
14 - User can use the IDL defined in Proto to create an automation app or script in a variety of languages without a language dependency.
16 ![image](https://media.github.sec.samsung.net/user/39889/files/ff684061-8bee-4a3f-855e-48ac38a5089a)
18 Please refer [grpc](https://grpc.io/) and [proto buffers](https://developers.google.com/protocol-buffers) for more information
25 <td> Name </td> <td> Description </td> <td> Proto definition </td> <td> Python usage </td>
30 <td valign="top"> killServer </td>
31 <td valign="top"> Terminate the org.tizen.aurum-bootstrap process </td>
32 <td valign="top"> rpc killServer(ReqEmpty) returns (RspEmpty) {} </td>
36 stub.killServer(ReqEmpty())
43 <td valign="top"> findElements </td>
44 <td valign="top"> If an object that satisfies a specific condition is searched on the screen and found, the object list is returned </td>
45 <td valign="top"> rpc findElements(ReqFindElements) returns (RspFindElements) {}<br><br>ReqFindElements :<br>elementId<br>automationid<br>textfield<br>widgetType<br>widgetstyle<br> ischecked<br>ischeckable<br>iscliackable<br>isenabled<br>isfocused<br>isfocusable<br>isscrollable<br>isselected<br>isshowing<br>isactive<br>mindepth<br>maxdepth<br>packagename<br>textpartialmatch<br>xpath<br>geometry</td>
49 #Find Clickable object.
50 def findClickableObject(stub):
51 response = stub.findElements(ReqFindElements(isClickable=True))
53 for el in response.elements:
58 #Find Object which has Button as text
59 def findButtonTextObject(stub):
60 response = stub.findElements(ReqFindElements(textField='Button'))
62 for el in response.elements:
63 response = stub.getValue(ReqGetValue(elementId=el.elementId))
64 return response.stringValue == 'Button'
68 #Find entry type object
69 def findEntryObject(stub):
70 response = stub.findElements(ReqFindElements(widgetType='Elm_Entry'))
72 if len(response.elements) <= 0: return False
76 #Find object with variouse condition
77 def findTextWithShowingObject(stub):
78 response = stub.findElements(ReqFindElements(textField='Bg', isShowing=True))
80 if len(response.elements) <= 0: return False
88 <td valign="top"> findElement </td>
89 <td valign="top"> If an object that satisfies a specific condition is searched on the screen and found, the object is returned </td>
90 <td valign="top"> rpc findElement(ReqFindElement) returns (RspFindElement) {}<br><br>ReqFindElement :<br>elementId<br>automationid<br>textfield<br>widgetType<br>widgetstyle<br> ischecked<br>ischeckable<br>iscliackable<br>isenabled<br>isfocused<br>isfocusable<br>isscrollable<br>isselected<br>isshowing<br>isactive<br>mindepth<br>maxdepth<br>packagename<br>textpartialmatch<br>xpath<br>geometry</td>
94 def findTextWithShowingObject(stub):
95 response = stub.findElements(ReqFindElements(textField='Bg', isShowing=True))
97 if response.element is None:
107 <td valign="top"> getValue </td>
108 <td valign="top"> Get the value of the object </td>
109 <td valign="top"> rpc getValue(ReqGetValue) returns (RspGetValue) {}<br><br>RspGetValue :<br>stringValue<br>intValue<br>doubleValue<br>boolValue </td>
113 def findButtonTextObject(stub):
114 response = stub.findElements(ReqFindElements(textField='Button'))
116 for el in response.elements:
117 response = stub.getValue(ReqGetValue(elementId=el.elementId))
118 return response.stringValue == 'Button'
127 <td valign="top"> setValue </td>
128 <td valign="top"> Set the value of the object </td>
129 <td valign="top"> rpc setValue(ReqSetValue) returns (RspSetValue) {}<br><br>RspGetValue :<br>stringValue<br>intValue<br>doubleValue<br>boolValue </td>
133 def setValueTest(stub):
134 response = stub.findElements(ReqFindElements(widgetType='Elm_Entry'))
136 if len(response.elements) <= 0: return False
138 targetObj = response.elements[0].elementId
139 testString = 'set test string by calling SetValue Method'
141 stub.setValue(ReqSetValue(elementId=targetObj, stringValue=testString))
142 response = stub.getValue(ReqGetValue(elementId=targetObj))
144 if response.stringValue != testString:
153 <td valign="top"> getSize </td>
154 <td valign="top"> Get geometry of the object </td>
155 <td valign="top"> rpc getSize(ReqGetSize) returns (RspGetSize) {} </td>
159 def getSizeTest(stub):
160 response = stub.findElements(ReqFindElements(textField='Button'))
161 print("els", response)
163 for el in response.elements:
164 response = stub.getSize(ReqGetSize(elementId=el.elementId))
167 return response.size.width + response.size.height > 0
176 <td valign="top"> clear </td>
177 <td valign="top"> Clear value of the object </td>
178 <td valign="top"> rpc clear(ReqClear) returns (RspClear) {} </td>
182 def setValueAndClearTest(stub):
183 response = stub.findElements(ReqFindElements(widgetType='Elm_Entry'))
185 if len(response.elements) <= 0: return False
187 targetObj = response.elements[0].elementId
188 testString = 'set test string by calling SetValue Method'
190 stub.setValue(ReqSetValue(elementId=targetObj, stringValue=testString))
191 response = stub.getValue(ReqGetValue(elementId=targetObj))
193 if response.stringValue != testString:
196 stub.clear(ReqClear(elementId=targetObj))
197 response = stub.getValue(ReqGetValue(elementId=targetObj))
198 if response.stringValue != '':
208 <td valign="top"> getAttribute </td>
209 <td valign="top"> Get attribute of the object </td>
210 <td valign="top"> rpc getAttribute(ReqGetAttribute) returns (RspGetAttribute) {}<br><br>ReqGetAttribute :<br>VISIBLE<br>FOCUSABLE<br>FOCUSED<br>ENABLED<br>CLICKABLE<br>SCROLLABLE<br> CHECKABLE<br>CHECKED<br>SELECTED<br>SELECTABLE<br>SHOWING<br>ACTIVE<br><br>RspGetAttribute :<br>stringValue<br>intValue<br>doubleValue<br>boolValue </td>
214 def getAttributeTest(stub):
215 response = stub.findElements(ReqFindElements(textField='Button'))
216 if len(response.elements) <= 0: return False
224 ['SCROLLABLE', False],
225 ['CHECKABLE', False],
233 for el in response.elements:
234 for attr in checkList:
235 if stub.getAttribute(ReqGetAttribute(elementId=el.elementId, attribute=attr[0])).boolValue != attr[1]:
238 if isFailed == True: return False
247 <td valign="top"> click </td>
248 <td valign="top"> Generate click event </td>
249 <td valign="top"> rpc click(ReqClick) returns (RspClick) {}<br><br>ReqClick :<br>elementId<br>coordination<br>Type :<br>ELEMENTID<br>COORD<br>ATSPI </td>
254 response = stub.findElements(ReqFindElements(textField='Accessibility'))
256 if len(response.elements) <= 0: return False
258 for el in response.elements:
259 stub.click(ReqClick(elementId=el.elementId, type='ELEMENTID'))
261 response = stub.findElements(ReqFindElements(textField='Screen Reader'))
262 if len(response.elements) <= 0: return False
264 for el in response.elements:
265 stub.click(ReqClick(coordination=Point(x=320, y=130), type='COORD'))
274 <td valign="top"> longClick </td>
275 <td valign="top"> Generate longclick (50ms) event </td>
276 <td valign="top"> rpc longClick(ReqClick) returns (RspClick) {} </td>
281 def longClickTest(stub):
282 stub.longClick(ReqClick(coordination=Point(x=160, y=160), type='COORD'))
291 <td valign="top"> flick </td>
292 <td valign="top"> Generate flick event </td>
293 <td valign="top"> rpc flick(ReqFlick) returns (RspFlick) {} </td>
299 for tryCnt in range(10):
300 print('Flick to bottom to find "Spinner" item @ tries:', tryCnt)
301 stub.flick(ReqFlick(startPoint=Point(x=160, y=359), endPoint=Point(x=160, y=1), durationMs=110))
302 response = stub.findElements(ReqFindElements(textField='Spinner', isShowing=True)
304 for el in response.elements:
314 <td valign="top"> touchDown </td>
315 <td valign="top"> Generate touchDown event </td>
316 <td valign="top"> rpc touchDown(ReqTouchDown) returns (RspTouchDown) {} </td>
321 res = stub.touchDown(ReqTouchDown(coordination=Point(x=160,y=640)))
325 if seq < 0: return False
327 for yy in range(640, 30, -10):
328 stub.touchMove(ReqTouchMove(coordination=Point(x=160,y=yy), seqId=seq))
330 stub.touchUp(ReqTouchUp(coordination=Point(x=160,y=30), seqId=seq))
339 <td valign="top"> touchMove </td>
340 <td valign="top"> Generate touchMove event </td>
341 <td valign="top"> rpc touchMove(ReqTouchMove) returns (RspTouchMove) {} </td>
352 <td valign="top"> touchUp </td>
353 <td valign="top"> Generate touchUp event </td>
354 <td valign="top"> rpc touchUp(ReqTouchUp) returns (RspTouchUp) {} </td>
365 <td valign="top"> installApp </td>
366 <td valign="top"> Install application </td>
367 <td valign="top"> rpc installApp(stream ReqInstallApp) returns (RspInstallApp) {} </td>
371 def installAppTest(stub):
372 response = stub.getAppInfo(ReqGetAppInfo(packageName='org.example.uicomponents'))
373 if (response.isInstalled): return True
375 tpkFile = './org.tizen.uicomponents.arm.tpk'
376 binaryChunk = get_file_chunks(tpkFile)
377 response = stub.installApp(binaryChunk)
379 for waitCnt in range(10):
380 response = stub.getAppInfo(ReqGetAppInfo(packageName='org.example.uicomponents'))
381 print('tries:', waitCnt, 'isInstalled:', response.isInstalled)
384 if response.isInstalled: return True
393 <td valign="top"> removeApp </td>
394 <td valign="top"> Remove application </td>
395 <td valign="top"> rpc removeApp(ReqRemoveApp) returns (RspRemoveApp) {} </td>
400 def removeAppTest(stub):
401 response = stub.getAppInfo(ReqGetAppInfo(packageName='org.example.uicomponents'))
402 if (response.isInstalled): response = stub.removeApp(ReqRemoveApp(packageName='org.example.uicomponents'))
404 for waitCnt in range(10):
405 response = stub.getAppInfo(ReqGetAppInfo(packageName='org.example.uicomponents'))
406 print('tries:', waitCnt, 'isInstalled:', response.isInstalled)
409 if response.isInstalled != True: return True
418 <td valign="top"> getAppInfo </td>
419 <td valign="top"> Get application info </td>
420 <td valign="top"> rpc getAppInfo(ReqGetAppInfo) returns (RspGetAppInfo) {}<br><br>ReqGetAppInfo :<br>isRunning<br>isInstalled<br>isFocused </td>
424 def getAppInfoTest(stub):
425 return stub.getAppInfo(ReqGetAppInfo(packageName='org.example.uicomponents')).isRunning
432 <td valign="top"> launchApp </td>
433 <td valign="top"> Launch application </td>
434 <td valign="top"> rpc launchApp(ReqLaunchApp) returns (RspLaunchApp) {} </td>
438 def launchAppTest(stub):
439 return stub.getAppInfo(ReqGetAppInfo(packageName='org.example.uicomponents')).isRunning
446 <td valign="top"> closeApp </td>
447 <td valign="top"> Close application </td>
448 <td valign="top"> rpc closeApp(ReqCloseApp) returns (RspCloseApp) {} </td>
459 <td valign="top"> getDeviceTime </td>
460 <td valign="top"> Get device time </td>
461 <td valign="top"> rpc getDeviceTime(ReqGetDeviceTime) returns (RspGetDeviceTime) {}<br><br>ReqGetDeviceTime :<br>SYSTEM<br>WALLCLOCK </td>
465 def getDeviceTimeTest(stub):
466 response1 = stub.getDeviceTime(ReqGetDeviceTime(type='SYSTEM'))
467 response2 = stub.getDeviceTime(ReqGetDeviceTime(type='WALLCLOCK'))
468 print(response1, response2)
470 return response2.timestampUTC > response1.timestampUTC;
477 <td valign="top"> sendKey </td>
478 <td valign="top"> Generate key event </td>
479 <td valign="top"> rpc sendKey(ReqKey) returns (RspKey) {}<br><br>ReqKey :<br>BACK<br>MENU<br>HOME<br>VOLUP<br>VOLDOWN<br>POWER<br>XF86<br>WHEELUP<br>WHEELDOWN<br> actionType :<br>STROKE<br>LONG_STROKE<br>PRESS<br>RELEASE<br>REPEAT<br><br>XF86KeyCode<br>durationMs<br>intervalMs</td>
483 def sendKeyTest(stub):
484 response = stub.sendKey(ReqKey(type='WHEELUP', actionType='STROKE'))
487 response = stub.sendKey(ReqKey(type='WHEELUP', actionType='STROKE'))
490 response = stub.sendKey(ReqKey(type='WHEELDOWN', actionType='STROKE'))
493 response = stub.sendKey(ReqKey(type='POWER', actionType='STROKE'))
496 response = stub.sendKey(ReqKey(type='POWER', actionType='STROKE'))
499 response = stub.sendKey(ReqKey(type='BACK', actionType='STROKE'))
509 <td valign="top"> takeScreenshot </td>
510 <td valign="top"> Take screenshot </td>
511 <td valign="top"> rpc takeScreenshot(ReqTakeScreenshot) returns (stream RspTakeScreenshot) {} </td>
515 def takeScreenshotTest(stub):
516 responses = stub.takeScreenshot(ReqTakeScreenshot())
517 image = open("screenshot.png", "wb")
519 for response in responses:
520 image.write(response.image)
530 <td valign="top"> dumpObjectTree </td>
531 <td valign="top"> Get object infomation </td>
532 <td valign="top"> rpc dumpObjectTree(ReqDumpObjectTree) returns (RspDumpObjectTree) {} </td>
536 def dumpObject(stub):
537 response = stub.findElements(ReqFindElements(textField='Bg', isShowing=True))
538 if len(response.elements) <= 0: return False
540 for ei in response.elements:
541 response = stub.dumpObjectTree(ReqDumpObjectTree(elementId=ei.elementId))
543 print(response.roots)
550 <td valign="top"> setFocus </td>
551 <td valign="top"> Set focus to specific UI Object </td>
552 <td valign="top"> rpc setFocus(ReqSetFocus) returns (RspSetFocus) {} </td>
558 response = stub.findElements(ReqFindElements(textField='Button'))
559 if len(response.elements) <= 0: return False
561 stub.setFocus(ReqSetFocus(elementId=response.elements[0).elementId)
568 <td valign="top"> actionAndWaitEvent </td>
569 <td valign="top"> Do action and wait event </td>
570 <td valign="top"> rpc actionAndWaitEvent(ReqActionAndWaitEvent) returns (RspActionAndWaitEvent) {}<br><br>ActionType :<br>CLICK<br>KEY<br>EventType<br> EVENT_WINDOW_ACTIVATE<br>EVENT_WINDOW_DEACTIVATE<br>EVENT_STATE_CHANGED_FOCUSED</td>
574 def actionAndWaitEvent(stub):
575 stub.actionAndWaitEvent(ReqActionAndWaitEvent(type=KEY, XF86keyCode='Return',
576 eventType=EVENT_STATE_CHANGE_FOCUSED, timeoutMs=1))
578 response = stub.findElements(ReqFindElements(textField='Button'))
579 if len(response.elements) <= 0: return False
581 stub.actionAndWaitEvent(ReqActionAndWaitEvent(type=CLICK, elementId=response.elements[0).elementId,
582 eventType=EVENT_WINDOW_ACTIVATE, timeoutMs=5))
592 grpc not support environment that uses proxy on host PC
596 The TV device and Host PC should be already connected through SDB
598 - Gets Aurum latest version and checkout to tizen branch
600 [Aurum Github](https://github.sec.samsung.net/tizen/aurum)
602 - Set up a python virtual environment and run UI Automation (working directory: aurum/)
604 (host) cd ui_automation/python/tv
606 #### Create virtual env
607 (host) python3 -m venv v
609 #### Activate a virtual env
611 (host) source v/bin/activate
613 (host) v/Scripts/activate.bat
615 #### Install required pkg (only once)
616 (python_virtual) pip3 install -r ../../../protocol/resources/python/requirements.txt
618 #### Generate aurum.proto file for python (only once)
619 (python_virtual) python3 -m grpc_tools.protoc --python_out=./ --grpc_python_out=./ -I ./../../../protocol/ ../../../protocol/aurum.proto
621 #### Target setup such as sdb forward, bootstrap execution
622 (python_virtual) python3 ../../../protocol/resources/python/tv/tvSetup.py
624 #### Then add your script then run it (Please refer sample scripts in 'aurum/protocol/resources/python/tv')
625 (python_virtual) python3 sampleWithUtils.py
627 #### Deactivate a virtual env
628 (python_virtual) deactivate
630 ### Reference and Tip
631 - [How to run aurum on TM1](https://code.sec.samsung.net/confluence/display/GFX/04.+NUITizenGallery+Test+Script+Guide)
632 - [NUI automation test](https://github.com/nui-dali/NUIAutomationTest)
633 - [Aurum test sciprts(samples)](https://github.sec.samsung.net/NUI/AurumTestScript)
634 - [Automation application(C++) in target](https://github.sec.samsung.net/TizenUIFW/aurum-test-sample)
635 * Aurum API is not public. we dont recommand direct calling aurum API in target.