diff options
Diffstat (limited to 'doc/ldtp-tutorial.rst')
-rw-r--r-- | doc/ldtp-tutorial.rst | 1496 |
1 files changed, 1496 insertions, 0 deletions
diff --git a/doc/ldtp-tutorial.rst b/doc/ldtp-tutorial.rst new file mode 100644 index 0000000..75974f9 --- /dev/null +++ b/doc/ldtp-tutorial.rst @@ -0,0 +1,1496 @@ +.. header:: + *Linux Desktop Testing Project – LDTP* + +.. footer:: + *Linux Desktop Testing Project – LDTP http://ldtp.freedesktop.org - page ###Page###* + + +====================================== +Linux Desktop Testing Project Tutorial +====================================== + + +:Date: 2014-03-29 +:Version: 1.1 +:Authors: Nagappan Alagappan <nagappan@gmail.com>, Harsha <nharsha@gmail.com>, +Premkumar J <prem.jothimani@gmail.com>, Guofu Xu <lavixu@gmail.com>, Surendran +M <suren.silverprince@gmail.com>, Vamsi B <vamsi1985@gmail.com>, Christopher +Bayliss <christopher.j.bayliss@gmail.com> +:Document: Linux Desktop Testing Project Tutorial + + + +Info +==== + +Copyright 2004 - 2007 Novell, Inc. + +Copyright 2008 - 12 Nagappan Alagappan + +Copyright 2014 Christopher Bayliss + +Permission is granted to copy, distribute and/or modify this document under the +terms of the GNU Lesser General Public License, Version 2 or any later version +published by the Free Software Foundation; with no Invariant Sections, no +Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included +in the section entitled "GNU Lesser General Public License". + +You should have received a copy of the GNU GNU Lesser General Public License +along with this documentation; if not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +.. contents:: Table of Contents + + +About LDTP +========== + +Linux Desktop Testing Project(LDTP) is aimed at producing a high quality +automated testing framework and cutting-edge tools that can be used to test +GNU/Linux Desktop to improve it. It uses the Accessibility libraries to poke +through the application's user interface. This idea has been extended to +Microsoft Windows as Cobra and Mac OS X as ATOMac. With this we can proudly +say; we have implemented a cross platform GUI testing tool. LDTP is now known +to work on Windows, Mac, Linux, Palm Source, Solaris, NetBSD and FreeBSD. + +The LDTP core framework uses Appmap(application map) and written test-cases to +test an application and gives the status of each test-case as the output. LDTP +can test any .NET/GNOME/KDE(QT >= 4.8) application which is accessibility +enabled, Mozilla, Open Office/Libre Office, and any Java application(should +have a UI based on swing). + +We encourage you to join the project and help us to create a robust, reliable +and stable test framework for Windows/Unix Desktops. Thanks to the Microsoft, +Apple, GNOME and Sun Microsystems Accessibility team for their great work and +their continuous support! + + +Audience +======== + +It is assumed that the user of this document has little knowledge about UI +controls in any GUI application and minimal Windows/Mac OS X/Linux or +Unix(Solaris/BSD) knowledge. + +About testing +============= + +Testing is a process to identify defects in a(software) system, for more +information see http://en.wikipedia.org/wiki/Software_testing. Testing an +application multiple times with the same steps can get rather slow and +annoying; therefore automating the process can do a better job. + +What is the complexity of GUI testing? + +* Identification of object in a window(push button, menu item). +* Should be context sensitive(Window specific operation). +* Handling of unexpected pop-up windows. +* Keeping the test script in sync with UI changes. +* Failures need to be verified on each operation. +* Rendering of images/text in the display area. + +What type of testing can be done using LDTP? + +LDTP can be used to test the functionality of any accessibility enabled +application. + +Advantage of accessibility based testing. + +* Accessibility libraries provide applications property, state, its child items etc. +* No need to work in toolkit(GTK, AWT, QT) level + +Disadvantage of accessibility based testing. + +* Application which are not accessibility enabled can't be tested. + +What applications can be tested? + +As of now, LDTP can test any .NET, GNOME applications which are accessibility +enabled, Mozilla, OpenOffice.org/Libreoffice, any Java application(should have +swing UI) and KDE applications based on QT 4.8. + + +Supported platforms +------------------- + +* openSuSE +* OpenSolaris +* Debian +* Madriva +* Ubuntu +* Fedora +* SLES +* SLED +* RHEL +* CentOS +* FreeBSD +* NetBSD +* Windows(XP SP3/Vista SP2/7 SP1/8) +* Mac OS X(>=10.6) +* Embedded Platform(Palm Source/Access Company) + + +Supported languages +------------------- + +* Python +* Clojure +* Java +* Ruby +* C# +* VB.NET +* Power Shell +* Perl + +LDTP Features +============= + +* LDTP concepts are derived from Software Automation Framework Support. +* LDTP supports verification of actions performed(guiexist(), verifystate, etc). +* Writing test scripts is very easy, and the script writer doesn't need to know + about the object hierarchy. +* CPU/Memory performance monitoring of application-under-test can be measured. + +LDTP on web +=========== + +Website: + http://ldtp.freedesktop.org + +Source/Binaries: + http://ldtp.freedesktop.org/wiki/Download + +API reference: + http://ldtp.freedesktop.org/wiki/Docs + +HOWTO: + http://ldtp.freedesktop.org/wiki/HOWTO + +FAQ: + http://ldtp.freedesktop.org/wiki/FAQ + +Dev mailing list: + http://lists.freedesktop.org/mailman/listinfo/ldtp-dev + +IRC: + #ldtp on irc.freenode.net + +Install LDTP +============ + +Disk space requirements +----------------------- + +Less than 450 KB(Linux), 5 MB(Windows) and 450 KB(Mac OS X) + +Software requirements +--------------------- + +Install the following dependency packages(Linux) + +* python-atspi or relevant name in your distribution. +* twisted-web or relevant name in your distribution. +* python-gnome or relevant name in your distribution. + +Install the following dependency packages(Mac OS X) + +* Xcode, if you plan to compile the software, else use egg from pypi. + +Optional packages(Linux) + +* Import tool of ImageMagick - To capture a screenshot. +* Python Imaging Library - Compare images, black out a region in an image. +* pystatgrab - CPU / Memory utilization monitoring library. + +Setup LDTP from scurce +---------------------- + +Download the source(Linux): + git clone https://github.com/ldtp/ldtp2; + cd ldtp2 + +Download the source(Windows): + git clone https://github.com/ldtp/cobra.git + +Download the source(Mac OS X): + git clone https://github.com/ldtp/pyatom.git; + cd pyatom + +Build and install LDTP on a Linux/Mac OS X environment: + python setup.py build + sudo python setup.py install + +Setup LDTP from binary +---------------------- + +Download latest Mac OS X, Windows, RPM, Deb, Gentoo, Solaris package from +http://ldtp.freedesktop.org/wiki/Download + +Architecture +============ + +LDTP Overall Architecture +------------------------- + +Test scripts uses LDTP API interface, which in-turn communicate to LDTP engine +either by UNIX socket or by TCP socket. LDTP engine talks to Application under +test(AUT) using AT-SPI library. + +LDTP Internals +-------------- + +LDTP Clients can talk to LDTP engine with XML RPC protocol. + +Most of LDTP ideas are implemented from http://safsdev.sf.net. Most commands +at-least 2 arguments. First argument will be context(window in which we want to +operate) and the second argument will be component(object in which we want to +operate, based on the current context). + +Example: click('\*-gedit', 'btnNew') # Click operation will be performed on a +window which is having \*-gedit(regexp) and in that window object name 'New', +which is of type 'push button'. + +.. image:: images/LDTP.png + :scale: 125 % + :alt: internals + :align: center + +Server +------ + +When a test script is started, the LDTP client will establish a connection with +the LDTP engine using AF_UNIX/AF_INET. + +Client Handler +-------------- + +Whenever a command is executed from the script, the client frames the XML data +and send it to the server. LDTP engine parses the command request from the +client and invoke the respective Component Handler. + +Component Handler +----------------- + +Each individual component handlers uses the AT-SPI libraries to communicate to +the respective application. Based on the execution status, success or failure +will be notified as a response(in XML format) to the client. In few cases the +requested data from the respective component will be returned to the client, +based on the request(example: gettextvalue). + +Event Handler +------------- + +For unexpected windows(example: connection reset by peer /connection timed out +dialogs) can be handled by registering a callback function and the respective +callback function will be called, whenever the registered window with the title +appears and even this window could be based on regular expression. + +LDTP conventions +================ + +Appmap +------ + +'Appmap' [Application Map in short] is a text based representation of the GUI +which is under testing. Each and every UI control viz., Button, Text Box etc., +are represented using predefined conventions(which are listed in the table +below) along with their parent UI object information. At runtime, a particular +UI control is accessed by using the Appmap generated for the GUI under testing. + +For more details about Appmap refer to: + +http://safsdev.sourceforge.net/DataDrivenTestAutomationFrameworks.htm#TheApplicationMap + +Appmap convention +----------------- + ++---------------------------------------+------------------------------------------+ +| *Class keywords* | *Convention used in appmap* | ++---------------------------------------+------------------------------------------+ +| ACCEL_LABEL | | ++---------------------------------------+------------------------------------------+ +| ALERT | dlg | ++---------------------------------------+------------------------------------------+ +| ANIMATION | | ++---------------------------------------+------------------------------------------+ +| ARROW | | ++---------------------------------------+------------------------------------------+ +| CALENDAR | cal | ++---------------------------------------+------------------------------------------+ +| CANVAS | cnvs | ++---------------------------------------+------------------------------------------+ +| CHECK_BOX | chk | ++---------------------------------------+------------------------------------------+ +| CHECK_MENU_ITEM | mnu | ++---------------------------------------+------------------------------------------+ +| COLOR_CHOOSER | | ++---------------------------------------+------------------------------------------+ +| COLUMN_HEADER | | ++---------------------------------------+------------------------------------------+ +| COMBO_BOX | cbo | ++---------------------------------------+------------------------------------------+ +| DATE_EDITOR | | ++---------------------------------------+------------------------------------------+ +| DESKTOP_ICON | | ++---------------------------------------+------------------------------------------+ +| DESKTOP_FRAME | frm | ++---------------------------------------+------------------------------------------+ +| DIAL | dial | ++---------------------------------------+------------------------------------------+ +| DIALOG | dlg | ++---------------------------------------+------------------------------------------+ +| DIRECTORY_PANE | | ++---------------------------------------+------------------------------------------+ +| DRAWING_AREA | dwg | ++---------------------------------------+------------------------------------------+ +| FILE_CHOOSER | dlg | ++---------------------------------------+------------------------------------------+ +| FILLER | flr | ++---------------------------------------+------------------------------------------+ +| FONT_CHOOSER | dlg | ++---------------------------------------+------------------------------------------+ +| FRAME | frm | ++---------------------------------------+------------------------------------------+ +| GLASS_PANE | | ++---------------------------------------+------------------------------------------+ +| HTML_CONTAINER | html | ++---------------------------------------+------------------------------------------+ +| ICON | ico | ++---------------------------------------+------------------------------------------+ +| IMAGE | img | ++---------------------------------------+------------------------------------------+ +| INTERNAL_FRAME | | ++---------------------------------------+------------------------------------------+ +| LABEL | lbl | ++---------------------------------------+------------------------------------------+ +| LAYERED_PANE | pane | ++---------------------------------------+------------------------------------------+ +| LIST | lst | ++---------------------------------------+------------------------------------------+ +| LIST_ITEM | lsti | ++---------------------------------------+------------------------------------------+ +| MENU | mnu | ++---------------------------------------+------------------------------------------+ +| MENU_BAR | mbar | ++---------------------------------------+------------------------------------------+ +| MENU_ITEM | mnu | ++---------------------------------------+------------------------------------------+ +| OPTION_PANE | opan | ++---------------------------------------+------------------------------------------+ +| PAGE_TAB | ptab | ++---------------------------------------+------------------------------------------+ +| PAGE_TAB_LIST | ptl | ++---------------------------------------+------------------------------------------+ +| PANEL | pnl | ++---------------------------------------+------------------------------------------+ +| PASSWORD_TEXT | txt | ++---------------------------------------+------------------------------------------+ +| POPUP_MENU | pop | ++---------------------------------------+------------------------------------------+ +| PROGRESS_BAR | pbar | ++---------------------------------------+------------------------------------------+ +| PUSH_BUTTON | btn | ++---------------------------------------+------------------------------------------+ +| RADIO_BUTTON | rbtn | ++---------------------------------------+------------------------------------------+ +| RADIO_MENU_ITEM | mnu | ++---------------------------------------+------------------------------------------+ +| ROOT_PANE | rpan | ++---------------------------------------+------------------------------------------+ +| ROW_HEADER | rhdr | ++---------------------------------------+------------------------------------------+ +| SCROLL_BAR | scbr | ++---------------------------------------+------------------------------------------+ +| SCROLL_PANE | scpn | ++---------------------------------------+------------------------------------------+ +| SEPARATOR | sep | ++---------------------------------------+------------------------------------------+ +| SLIDER | sldr | ++---------------------------------------+------------------------------------------+ +| SPIN_BUTTON | sbtn | ++---------------------------------------+------------------------------------------+ +| SPLIT_PANE | splt | ++---------------------------------------+------------------------------------------+ +| STATUS_BAR | stat | ++---------------------------------------+------------------------------------------+ +| TABLE | tbl | ++---------------------------------------+------------------------------------------+ +| TABLE_CELL | tbl | ++---------------------------------------+------------------------------------------+ +| TABLE_COLUMN_HEADER | tch | ++---------------------------------------+------------------------------------------+ +| TABLE_ROW_HEADER | trh | ++---------------------------------------+------------------------------------------+ +| TEAROFF_MENU_ITEM | tmi | ++---------------------------------------+------------------------------------------+ +| TERMINAL | term | ++---------------------------------------+------------------------------------------+ +| TEXT | txt | ++---------------------------------------+------------------------------------------+ +| TOGGLE_BUTTON | tbtn | ++---------------------------------------+------------------------------------------+ +| TOOL_BAR | tbar | ++---------------------------------------+------------------------------------------+ +| TOOL_TIP | ttip | ++---------------------------------------+------------------------------------------+ +| TREE | tree | ++---------------------------------------+------------------------------------------+ +| TREE_TABLE | ttbl | ++---------------------------------------+------------------------------------------+ +| UNKNOWN | unk | ++---------------------------------------+------------------------------------------+ +| VIEWPORT | view | ++---------------------------------------+------------------------------------------+ +| WINDOW | dlg | ++---------------------------------------+------------------------------------------+ +| EXTENDED | | ++---------------------------------------+------------------------------------------+ +| HEADER | hdr | ++---------------------------------------+------------------------------------------+ +| FOOTER | foot | ++---------------------------------------+------------------------------------------+ +| PARAGRAPH | para | ++---------------------------------------+------------------------------------------+ +| RULER | rul | ++---------------------------------------+------------------------------------------+ +| APPLICATION | app | ++---------------------------------------+------------------------------------------+ +| AUTOCOMPLETE | txt | ++---------------------------------------+------------------------------------------+ +| CALENDARVIEW | cal | ++---------------------------------------+------------------------------------------+ +| CALENDAREVENT | cal | ++---------------------------------------+------------------------------------------+ +| EDITBAR | txt | ++---------------------------------------+------------------------------------------+ +| ENTRY | txt | ++---------------------------------------+------------------------------------------+ + +Example Applications +==================== + +Examples will use gedit. You can download it from +https://wiki.gnome.org/Apps/Gedit#Download. + +If you are using a linux distro, the install gedit with you package manager. + +How to Access UI Objects from LDTP scripts +========================================== + +There are two main entities to act on an object: window name and object name. + +Window name +----------- + +To operate on a window, we need to know the window name(nothing but the window title). + +Different window types +~~~~~~~~~~~~~~~~~~~~~~ + +1. Frame(frm) +2. Dialog(dlg) +3. Alert(dlg) +4. Font Chooser(dlg) +5. File Chooser(dlg) +6. Window(This type in general does not have any associated title, so we need + to represent them using index - dlg) + +Glob pattern support +~~~~~~~~~~~~~~~~~~~~ + +Window name can be clubbed with glob patterns(* or ?) + +EXAMPLE: + 1. \*-gedit means the title has -gedit in it, BUT can have anything before + it or after it. + 2. ????-gedit means the title has -gedit in it, AND has four cractors + before it. + + .. NOTE:: You can use \* or ? anywhere for the title name. + + +Different ways of representing window name +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Window type and window title(Ex: 'frmnew1-') +2. Window title(Ex: 'Unsaved Document 1 - gedit\*') +3. Window type, glob expression and partial window title(Ex: 'frm\*-gedit') +4. Glob pattern and partial window title(Ex: '\*-gedit') +5. Window type, partial window title and glob pattern(Ex: 'frmnew1\*') +6. Window type, window title and index(If two windows of same title exist at + same time. Ex: First window name 'dlgAppoinment', Second window name + 'dlgAppoinment1') +7. Window type and index(only if window does not have any accessible title, Ex: + 'dlg0') + +Window name formats +~~~~~~~~~~~~~~~~~~~ + +If window label contains space or new line characters, they will be stripped. + +Example: + 1. 'saved-doc - gedit\*', will be represented as 'saved-doc-gedit\*' + 2. 'Unsaved Document 1 - gedit*', will be represented as + 'UnsavedDocument1-gedit\*' + +Object name +----------- + +Object(the type of control in which we want to operate) can be identified +either with a label or by an associated label. + +Label +~~~~~ + +In general menu/menu item/push button/toggle button type controls can be +accessed through its label. + +Example: + +.. code-block:: python + + mnuFile #(gedit menu) + mnuNew #(gedit menu item) + btnNew #(gedit tool bar, push button) + tbtnLocation #(gedit Open File dialog, toggle bar control) + +Label by/for(associated label) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In general text/tables/check box/radio button/spin button/combo box controls +can be accessed using the associated label only. + +Example: + +.. code-block:: python + + txtLocation #(gedit Open File dialog, text control) + tblFiles #(gedit Open File dialog, table control) + cboSearchfor #(gedit Find dialog, combo box control) + chkMatchcase #(gedit Find dialog, check box control) + sbtnRightmarginatcolumn #(gedit Preferences dialog, spin button control) + +Object name with out label/associated label accessing via index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a control does not have any label or associated label, then it can be +accessed using index. + +Example: + +.. code-block:: python + + txt0 #(gedit text rendering region) + ptl0 #(gedit Preferences dialog, page tab list control) + ptl0 #(In gedit when more than one files are opened, + # a page tab list control will be available) + +Object name with index +~~~~~~~~~~~~~~~~~~~~~~ + +In some cases, a control type can be present in multiple places in the same +window and chances that it may have same label too in that case, the first +control can be accessed just with the default notation, but the second control +and further can be accessed with the format control type, label or associated +label and index starting from 1. + +Example: + +.. code-block:: python + + btnAdd #First push button control with label Add + btnAdd1 #Second push button control with label Add + btnAdd2 #Third push button control with label Add + +Object name with window id(Windows only) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Object can be identified with window id, which is unique across all the +application that are currently running, even on i18n/l10n environment. Object +name when passed to the API, it should start with # and then the unique number, +for the widget. + +Example:: + + #1234 #With Visual UI Verify this is represented as Automation Id + +Object identification with object type and index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On a window, identify the control with index of widget type. Object name format +passed should be, LDTP convention object type and object index, respective to +the given object type. + +Example:: + + btn#0 – First button on the current window + txt#1 – Second text widget on the current window + +Object name formats +~~~~~~~~~~~~~~~~~~~ + +If object label or associated label contains space, dot, colon, under score or +new line characters, they will be stripped. + +Example:: + + 'Search for:' will be represented as 'Searchfor' + 'File name 'a_txt' already exist. + Replace' will be represented as 'Filename'atxt'alreadyexistReplace'. + +Accessibility library +===================== + +LDTP uses accessibility libraries(at-spi) available in GNOME environment. Using +accessibility we can get the information about the application and its current +state(property). We can be able to poke through each layer in any application, +if and only if, the application has accessibility enabled. + +Enabling accessibility +====================== + +**GNOME 2.x:** Go to System > Preferences > Assistive Technologies and enable +Assistive Technology. + +**GNOME 3.x:** Run the following command from command line to enable accessibility + +.. code-block:: bash + + gsettings set org.gnome.desktop.interface toolkit-accessibility true + +**Microsoft Windows:** No need to change any settings, as accessibility is +enabled by default. + +**Mac OSX:** System wide accessibility must be enabled. Check the check box: +System Preferences > Universal Access > Enable access for assistive devices. +Failure to enable this will result in ErrorAPIDisabled exceptions during some +module usage. + +Drawing 2: Screenshot of Assisstive technology preferences dialog + +Importing LDTP modules +====================== + +We prefer to import everything, if we do we can just directly use all the ldtp +functions just by calling their name. If we import the module as 'import ldtp', +then we need to call the corresponding function as ldtp.<function_name> + +To import ldtp in python, do: + +.. code-block:: python + + >>> from ldtp import * + >>> from ldtputils import * + >>> from ooldtp import * + +Example 1: + +.. code-block:: python + + >>> from ldtp import * + >>> selectmenuitem('\*-gedit', 'mnuFile;mnuNew') + + +Example 2: + +.. code-block:: python + + #!/usr/bin/python + + # The standard import stuff. + from ldtp import * + from ooldtp import context as locate + from time import sleep + + # Here we open the app. + launchapp('gedit') + + # Now we find it and make sure it is open. + gedit_win = locate('\*gedit') + gedit_win.waittillguiexist() + + # Now we type into gedit. + text_field = gedit_win.getchild('txt1') + text_field.enterstring("G'Day mate!") + + # Save a picture to prove we did it. + imagecapture('\*gedit', '/tmp/foo.png') + + # Quit gedit. + quit = gedit_win.getchild('mnuQuit') + quit.selectmenuitem() + + # Close without saving. + dont_save = locate('Question') + dont_save.waittillguiexist() + + button = dont_save.getchild('btnClosewithoutSaving') + button.click() + + # Wait until gedit is gone. + gedit_win.waittillguinotexist()() + + +Call a function to perform an operation +--------------------------------------- + +LDTP generally operates on the given object in a particular window. + +To select a menu item, you need to call the selectmenuitem function. For +example, to select open menu item in gedit application, call the below +function: + +.. code-block:: python + + >>> selectmenuitem('frmUnsavedDocument1-gedit', 'mnuFile;mnuOpen') + +When you call the above a new dialog box will be poped up, you can verify +whether the window is opened or not either by guiexist() or by +waittillguiexist(). + +.. NOTE:: The guiexist() function immediately returns either 1(window exist) or + 0(window does not exist), waittillguiexist() waits for the window to + appear. Wait time out is by default 30 seconds. This default time + out can be either increased on decreased using GUI_TIMEOUT. + +If you want to operate on a push button in a window, you need to call click(), +e.g.: To press 'Cancel' button in a GTK Open File Selector dialog: + +.. code-block:: python + + >>> click('dlgOpenFile', 'btnCancel') + +When you do the above operation the GTK File selector dialog disappears. To +verify whether the window actually quits or not use: + +.. code-block:: python + + >>> waittillguinotexist()() + +If you modify any opened file in gedit, the window title will be modified. To +continue operating on the window you need to change your context of operation. +Reason: As you are aware that LDTP works based on individual window, the +context of window will be changed, when the title changes. To over come this +use: + +.. code-block:: python + + >>> setcontext() + +and when you don't require them use: + +.. code-block:: python + + >>> releasecontext() + +Edit your current opened file using: + +.. code-block:: python + + >>> settextvalue('frmUnsavedDocument1-gedit', 'txt0', 'Testing editing') + +This will change the window title. Note, before doing the above operation, +title will be 'Unsaved Document 1 - gedit' and after editing the title will +look like '\*Unsaved Document 1 - gedit'. To further +operate on the same window, use: + +.. code-block:: python + + >>> setcontext('Unsaved Document 1 - gedit', '\*Unsaved Document 1 - gedit') + +So that you can continue using the same window name, for example: + +.. code-block:: python + + >>> selectmenuitem('frmUnsavedDocument1-gedit', 'mnuFile;mnuSaveAs') + +The above function will invoke the GTK save dialog box. If any of the action +releated functions(example: selectmenuitem, click, settextvalue) fail, an +exception is raised. It has to be handled by the program to either continue +operating on execution or just halt. + +LDTP API +-------- + +Refer LDTP API page for list of implemented LDTP API's + +Using/Hacking LDTP +================== + +Identifying controls +-------------------- + +To operate on a window, first thing we need to know is the window title. + +In the following picture you could notice red colored eclipse mark is the +window title. + +.. code-block:: python + + >>> from ldtp import * + >>> guiexist('\*-gedit') + 1 + >>> guiexist('frmUnsavedDocument1-gedit') + 1 + >>> guiexist('frmUnsavedDocument1-*') + 1 + >>> guiexist('frm*-gedit') + 1 + >>> guiexist('Unsaved Document 1 - gedit') + 1 + +Push button +----------- + +To operate on an object inside gedit window, we need to know the object +information. + +To click on open push button in gedit tool bar control, we need to use click +API with window name as first argument and object name as second argument. The +above command does the click operation. Information to be gathered is Window +name(Unsaved Document 1 – gedit) and push button control(Open). + +.. code-block:: python + + >>> from ldtp import * + >>> click('\*-gedit', 'btnOpen') + 1 + +Menu item +--------- + +To select a menu item under a menu in a window we need to use selectmenuitem +API. + +Informations to be gathered: Window name(Unsaved Document 1 – gedit), menu +control(File), menu item control(New). + +Incase of menu, we handle them in hierarchy. So, to access 'New' menu item, we +need 'File' menu control too. + +.. code-block:: python + + >>> from ldtp import * + >>> selectmenuitem('\*-gedit', 'mnuFile;mnuNew') + 1 + +Toggle button +------------- + +To operate on a toggle button with a click action, information required are +window name(Open Files...) toggle button control(Type a file name). + +.. code-block:: python + + >>> from ldtp import * + >>> click('dlgOpenFiles...', 'tbtnTypeafilename') + 1 + +Text control +------------ + +To set a text value in a text box, information like window name(Open Files...), +text controls associated label(Location:) and the actual text to be +placed(Class1.cs). + +.. code-block:: python + + >>> from ldtp import * + >>> settextvalue('dlgOpenFiles...', 'txtLocation', 'Class1.cs') + 1 + +Table control +------------- + +To select a row from the table of GTK open file selector, we need to collect +information like, Window name(Open Files...), table name(Files – circled with +blue color), row to be selected(Class1.cs). + +.. code-block:: python + + >>> from ldtp import * + >>> selectrow('dlgOpenFiles...', 'tblFiles', 'Class1.cs') + 1 + +Push button +----------- + +After selecting the file name, to open the file contents, we need to click on +Open push button control. For doing this operation we need to gather +informations like Window name(Open Files...), push button label name(Open). + +.. code-block:: python + + >>> from ldtp import * + >>> click('dlgOpenFiles...', 'btnOpen') + 1 + +Check box +--------- + +To click on a check box control, we need to collect informations like window +name(gedit Preferences), check box associated label name(Display line numbers). + +.. code-block:: python + + >>> from ldtp import * + >>> click('dlggeditPreferences', 'chkDisplaylinenumbers') + 1 + +.. code-block:: python + + >>> from ldtp import * + >>> check('dlggeditPreferences', 'chkEnabletextwrapping') + 1 + +.. code-block:: python + + >>> from ldtp import * + >>> uncheck('dlggeditPreferences', 'chkDisplaylinenumbers') + 1 + +Spin button +----------- + +To operate on a spin button, we need to collect information like Window +name(gedit Preferences), spin button control name(Right margin at column). + +.. code-block:: python + + >>> from ldtp import * + >>> getvalue('dlggeditPreferences', 'sbtnRightmarginatcolumn') + 80.0 + >>> setvalue('dlggeditPreferences', 'sbtnRightmarginatcolumn', '81') + 1 + >>> setvalue('dlggeditPreferences', 'sbtnRightmarginatcolumn', '80') + 1 + +Page tab +-------- + +To operate on a page tab list, we need to collect information like window +name(gedit Preferences), page tab list name(ptl0 in this case, as there are no +label or associated label with this page tab list control), page tab name or +index starting from 0. + +.. code-block:: python + + >>> from ldtp import * + >>> gettabcount('dlggeditPreferences', 'ptl0') + 5 + >>> selecttabindex('dlggeditPreferences', 'ptl0', 2) + 1 + >>> selecttab('dlggeditPreferences', 'ptl0', 'Editor') + 1 + +Check menu item +--------------- + +To operate on check menu item, we need to gather information like window +name(Unsaved Document 1 – gedit), menu name(View), check menu item name(Side +Pane). + +.. code-block:: python + + >>> from ldtp import * + >>> selectmenuitem('\*-gedit', 'mnuView;mnuSidePane') + 1 + >>> menuuncheck('\*-gedit', 'mnuView;mnuSidePane') + 1 + +.. code-block:: python + + >>> from ldtp import * + >>> menucheck('\*-gedit', 'mnuView;mnuStatusbar') + 1 + +Radio menu item +--------------- + +To operate on a radio menu item control, we need to gather informations like +window name(Unsaved Document 1 – gedit), menu name(Documents), menu item +name(Class1.cs – assuming that Class1.cs is currently opened). + +.. code-block:: python + + >>> from ldtp import * + >>> selectmenuitem('\*-gedit', 'mnuDocuments;mnuClass1.cs') + 1 + >>> menucheck('\*-gedit', 'mnuDocuments;mnuClass1.cs') + 1 + +Combo box – Menu item +--------------------- + +To select a menu item under a combo box, we need to gather informations like +window name(Open Files...), combo box name(Character Coding), menu item +name(Current Locale). + +.. code-block:: python + + >>> from ldtp import * + >>> comboselect('dlgOpenFiles...', 'cboCharacterCoding', 'Current Locale(UTF-8)') + 1 + +Combo box – List item +--------------------- + +To operate on list item under a combo box control, we need to gather +informations like window name(Find), Combo box control name(Search for), list +item existing content or list item index or new item +name(OdbcMetaDataCollectionName.cs) + +.. code-block:: python + + >>> from ldtp import * + >>> settextvalue('dlgFind', 'cboSearchfor', 'OdbcMetaDataCollectionNames.cs'') + 1 + +.. code-block:: python + + >>> from ldtp import * + >>> comboselect('dlgFind', 'cboSearchfor', 'OdbcMetaDataCollectionNames.cs') + 1 + +Launch application +------------------ + +Application to be tested can be launched using LDTP API launchapp. + +.. code-block:: python + + >>> from ldtp import * + >>> launchapp('gedit') + 1 + +GUI exist +--------- + +To check a GUI(window) exist, you can use this guiexist() API. Also it has +different flavors like waittillguiexist(), waittillguinotexist(). + +guiexist() function checks whether the given window exists or not. If exist +returns 1, else returns 0. + +waittillguiexist() function will wait for the given window to appear. If +appeared returns 1, else returns 0. Difference between guiexist() and +waittillguiexist() is, guiexist() returns immediately, but waittillguiexist() +will wait for a max of 30 seconds for a window to appear. Note: On doing some +operation, if the expected result is, a window will be pop-ed up, then it is +recommended to use waittillguiexist(), instead of wait or sleep. Reason: wait +or sleep will wait till the time period, but waittillguiexist(), will return +immediately once the window appears. + +waittillguinotexist() function will wait for the given window to close. If +closed returns 1, else returns 0. waittillguinotexist() will wait for a max of +30 seconds for a window to close. Note: On doing some operation, if the +expected result is, an existing window will be closed, then it is recommended +to use waittillguinotexist(), instead of wait or sleep. Reason: wait or sleep +will wait till the time period, but waittillguinotexist(), will return +immediately once the window closed. + +Timeout +------- + +GUI timeout +~~~~~~~~~~~ + +GUI timeout, is the default timeout settings used, by waittillguiexist() and +waittillguinotexist() functions. This function will wait for the specified +number of seconds, for the window to either appear or disappear. Default +timeout period is 30 seconds. + +This default timeout period that can be modified: + +* By setting the environment variable GUI_TIMEOUT to whatever seconds. +* By passing a value to guiTimeOut argument of waittillguiexist() or + waittillguinotexist() functions. +* By calling guitimeout function. +* When invoking LDTP engine, use -g option. + +*Example 1* + +.. code-block:: bash + + export GUI_TIMEOUT=30 + +*Example 2* + +.. code-block:: python + + waittillguiexist('\*-gedit', guiTimeOut=30) + waittillguinotexist('dlgOpenFiles...', guiTimeOut=30) + +*Example 3* + +.. code-block:: python + + guitimeout(30) + +*Example 4* + +.. code-block:: bash + + ldtp -g 30 + +OBJ timeout +~~~~~~~~~~~ + +OBJ timeout, is the default timeout settings used, internally. This function +will wait for the specified number of seconds, for the object inside a window +to appear. Default timeout period is 5 seconds. + +This default timeout period that can be modified: + +* By setting the environment variable OBJ_TIMEOUT to whatever seconds. +* By calling objtimeout function. +* When invoking LDTP engine, use -o option. + +*Example 1* + +.. code-block:: bash + + export OBJ_TIMEOUT=5 + +*Example 2* + +.. code-block:: python + + objtimeout(5) + +*Example 3* + +.. code-block:: bash + +ldtp -o 5 + + +Generate raw keyboard events +---------------------------- + +In some cases, the window we are trying to operate may not be accessibility +enabled or we may need to generate non-printable keys(ALT, CTRL, ENTER, +BACKSPACE, ESC, F1-F12, SHIFT, CAPS LOCK, TAB, PAGE UP, PAGE DOWN, HOME, END, +RIGHT / LEFT / UP / DOWN ARROW KEYS, INS, DEL). We can use generatekeyevent +function or enterstring function to simulate the key events, as if the user +typed. Note: All the non-printable characters will be enclosed with in angular +brackets. + +*Example 1* + +.. code-block:: python + + <ctrl>lwww.google.co.in<enter> + +*Example 2* + +.. code-block:: python + + <alt><f1> + +*Example 3* + +.. code-block:: python + + <control>s + +.. code-block:: python + + >>> from ldtp import * + >>> launchapp('gedit') + 1 + >>> waittillguiexist('\*-gedit') + 1 + >>> enterstring('<alt><tab>') + 1 + >>> enterstring('\*-gedit', 'txt0', '<caps>Testing enterstring API<enter>') + 1 + >>> generatekeyevent('<alt><tab>') + 1 + +Generate raw mouse events +------------------------- + +To generate raw mouse events of different types like, b1c, b1d, b2c, b2d, b3c, +b3d, X and Y of screen co-ordinates has to be provided. Here b is button, c is +single click, d is double click. + +.. code-block:: python + + >>> from ldtp import * + >>> generatemouseevent(100, 200) # Default is b1c + 1 + >>> generatemouseevent(100, 200, 'b1d') # To generate double click + 1 + +Application information +----------------------- + +On calling getapplist, will get all the accessibility application name that are +currently running. To get window list for which the application map's are +gathered and stored in local cache, use getwindowlist. To get all the object +list under a window, use getobjectlist API. To get a list of properties +available under an object, use getobjectinfo. To get the property of an object, +use getobjectproperty. + +.. code-block:: python + + >>> from ldtp import * + >>> getapplist() + [u'gnome-session', u'gnome-power-manager', u'gnome-settings-daemon', u'Libbonoboui-Gtk-Module-init-info', + u'nautilus', u'GnomeApplicationBrowser', u'/usr/lib/zen-updater/ZenUpdater.exe', u'gaim', + u'gtk-window-decorator', u'gedit', u'xchat', u'gnome-panel', u'gnome-volume-manager', u'resapplet', + u'nm-applet', u'soffice.bin'] + >>> getwindowlist() + [u'frmUnsavedDocument1-gedit'] + >>> getobjectlist('\*-gedit') + ... + >>> getobjectinfo('\*-gedit', 'btnNew') + [u'child_index', u'class', u'description', u'parent', u'label'] + >>> getobjectproperty('\*-gedit', 'btnNew', 'class') + 'New' + +Callback – On new window creation +--------------------------------- + +Register a callback event, when a window with given title is created. Glob type +pattern can be given as title name. + +Advantage +--------- + +Unexpected window can be easily handled using this. For example, the password +dialog box of Evolution, connection reset by peer dialog, application crash +dialog, etc. + +Example +------- + +.. code-block:: python + + from ldtp import * + import threading + # Thread creation + callbackRunning = threading.Event() + callbackRunning.clear() + callbackState = threading.Event() + callbackState.clear() + # Callback definition + def cb(): + callbackState.set() + waittillguiexist('dlgReplace') + click('dlgReplace', 'btnClose') + callbackState.clear() + callbackRunning.set() + print 'callbackend' + # Callback registration + onwindowcreate('Replace', cb) + # General operation, which will invoke a window + click('\*gedit', 'btnReplace') + click('\*gedit', 'btnOpen') + waittillguiexist('dlgOpenFiles...') + click('dlgOpenFiles...', 'btnClose') + # Wait for callback to complete, if invoked + if callbackState.isSet(): + print 'Waiting for callback to complete' + callbackRunning.wait() + print 'callbackset' + print 'test end' + +Logging +------- + +.. code-block:: python + + >>> from ldtp import * + >>> log('test script', 'debug') + 1 + >>> log('test script', 'warning') + 1 + >>> log('test script', 'error') + 1 + >>> log('test script', 'cause') + 1 + +Example script +============== + +.. code-block:: python + + from ldtp import * + from ldtputils import * + + try: + launchapp('gedit') + if waittillguiexist('\*-gedit') == 0: + raise LdtpExecutionError('Gedit window does not exist') + selectmenuitem('\*-gedit', 'mnuFile;mnuOpen') + if waittillguiexist('dlgOpenFiles') == 0: + raise LdtpExecutionError('Open Files dialog does not exist') + selectrow('dlgOpenFiles...', 'tblFiles', fileName [0]) + click('dlgOpenFiles...', 'btnOpen') + if waittillguinotexist('dlgOpenFiles') == 0: + raise LdtpExecutionError('Open Files dialog still exist') + except LdtpExecutionError, msg: + raise + +How to execute LDTP scripts +=========================== + +Make sure that you have the following files in current working directory +You need to have test scripts to be executed + +Invoking python script + +.. code-block:: bash + + $ python <script-file-name.py> + +Example + +.. code-block:: python + + $ python gedit.py + +Suggestions from LDTP team +========================== + +When a new window is expected after an operation, we suggest to use +waittillguiexist() and on some operation, if a window is expected to close we +suggest to use waittillguinotexist(). In both cases, the time-out period is 30 +seconds. This value can be modified – refer LDTP API reference. + +How to operate LDTP from a remote system +======================================== + +LDTP engine(Linux) +------------------- + +Follow one of the options to start LDTP engine(ldtp binary) in the remote box + +*Option 1* + +.. code-block:: bash + + $ ldtp -p + +*Option 2* + +.. code-block:: bash + + $ ldtp -p <port number to start> # Default port number is 4118 + +LDTP engine(Windows) + +Execute CobraWinLDTP.exe in command line + +LDTP engine(Mac OS X) + +Execute ldtp in command line + +LDTP client + +Follow one of the options in the client side to communicate to LDTP engine + +*Option 1* + +.. code-block:: bash + + export LDTP_SERVER_ADDR=host-name or ip address + export LDTP_SERVER_PORT=<port number to communicate, as mentioned in LDTP engine> + python <script file name>.py or ldtprunner test-runner.xml + +*Option 2* + +.. code-block:: bash + + export LDTP_SERVER_ADDR=host-name or ip address + python <script file name>.py or ldtprunner test-runner.xml # This will use default port number. + + +Troubleshooting LDTP +==================== + +In-case, if you want to see whats happening on executing some LDTP commands, +follow these steps. + +In a terminal: + +.. code-block:: bash + + $ export LDTP_DEBUG=2 # If bash shell(Linux/Mac OS X) + C:\> set LDTP_DEBUG=1(Microsoft Windows) + $ ldtp #(Linux/Mac OS X) on Windows run CobraWinLDTP.exe + Client packet len: 82 + i = 0 + Data read 82, packet-len = 82, bytes read = 82, data: <?xml version="1.0"?><REQUEST> + <ACTION>124</ACTION><ID>MainThread124</ID></REQUEST> + PACKET LENGTH: 0 + Received packet [<?xml version="1.0"?><REQUEST><ACTION>124</ACTION><ID>MainThread124 + </ID></REQUEST>] through 15 + Node: ACTION + action_name: 124 + Node: ID + request_id: MainThread124 + Command: 124 + Accessible application name: Thunderbird + Accessible application name: gnome-panel + Accessible application name: xchat + Accessible application name: nm-applet + Accessible application name: nautilus + Accessible application name: gaim + Accessible application name: acroread + Accessible application name: soffice.bin + Accessible application name: gtk-window-decorator + Accessible application name: gedit + LIST: <?xml version="1.0" encoding="utf-8"?><OBJECTLIST><OBJECT>nautilus</OBJECT> + <OBJECT>gaim</OBJECT><OBJECT>gtk-window-decorator</OBJECT><OBJECT>gedit</OBJECT> + <OBJECT>xchat</OBJECT><OBJECT>gnome-panel</OBJECT><OBJECT>Thunderbird</OBJECT> + <OBJECT>nm-applet</OBJECT><OBJECT>soffice.bin</OBJECT><OBJECT>acroread</OBJECT></OBJECTLIST> + resp_len = 117 + Sending.. + 538 + Response packet: <?xml version="1.0" encoding="utf-8"?><RESPONSE><ID>MainThread124</ID> + <STATUS><CODE>0</CODE><MESSAGE>Successfully completed</MESSAGE></STATUS> + <DATA><LENGTH>325</LENGTH><VALUE><![CDATA[<?xml version="1.0" encoding="utf-8"?><OBJECTLIST> + <OBJECT>nautilus</OBJECT><OBJECT>gaim</OBJECT><OBJECT>gtk-window-decorator</OBJECT> + <OBJECT>gedit</OBJECT><OBJECT>xchat</OBJECT><OBJECT>gnome-panel</OBJECT> + <OBJECT>Thunderbird</OBJECT><OBJECT>nm-applet</OBJECT><OBJECT>soffice.bin</OBJECT> + <OBJECT>acroread</OBJECT></OBJECTLIST>]]></VALUE></DATA></RESPONSE> + Msg: + Bytes sent: 542 + +In another terminal: + +.. code-block:: bash + + $ export LDTP_DEBUG=2 # If bash + +.. code-block:: python + + nags@nags:~> python + Python 2.5(r25:51908, Nov 25 2006, 15:39:45) + [GCC 4.1.2 20061115(prerelease)(SUSE Linux)] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + >>> from ldtp import * + >>> getapplist() + 124( ) + Send packet <?xml version="1.0"?><REQUEST><ACTION>124</ACTION><ID>MainThread124</ID></REQUEST> + Received packet size 538 + Received response Packet <?xml version="1.0" encoding="utf-8"?><RESPONSE><ID>MainThread124</ID> + <STATUS><CODE>0</CODE><MESSAGE>Successfully completed</MESSAGE></STATUS><DATA> + <LENGTH>325</LENGTH><VALUE><![CDATA[<?xml version="1.0" encoding="utf-8"?><OBJECTLIST> + <OBJECT>nautilus</OBJECT><OBJECT>gaim</OBJECT><OBJECT>gtk-window-decorator</OBJECT> + <OBJECT>gedit</OBJECT><OBJECT>xchat</OBJECT><OBJECT>gnome-panel</OBJECT> + <OBJECT>Thunderbird</OBJECT><OBJECT>nm-applet</OBJECT><OBJECT>soffice.bin</OBJECT> + <OBJECT>acroread</OBJECT></OBJECTLIST>]]></VALUE></DATA></RESPONSE> + [u'nautilus', u'gaim', u'gtk-window-decorator', u'gedit', u'xchat', u'gnome-panel', + u'Thunderbird', u'nm-applet', u'soffice.bin', u'acroread'] + >>> + +Bibliography +============ + +http://en.wikipedia.org/wiki/Software_testing + +http://safsdev.sf.net |