Merge lp:~cellsoftware/telegram-app/autopilotTest-4 into lp:telegram-app

Proposed by Paz Chauhan
Status: Merged
Approved by: Jin
Approved revision: 250
Merged at revision: 247
Proposed branch: lp:~cellsoftware/telegram-app/autopilotTest-4
Merge into: lp:telegram-app
Diff against target: 3409 lines (+2757/-37)
35 files modified
README.md (+191/-35)
buildScripts/click.sh (+10/-0)
setup.sh (+17/-1)
telegram/app/qml/AccountContactsPage.qml (+5/-1)
telegram/app/qml/AccountDialogList.qml (+2/-0)
telegram/app/qml/AccountDialogPage.qml (+4/-0)
telegram/app/qml/AccountMessageList.qml (+2/-0)
telegram/app/qml/AccountMessageMedia.qml (+1/-0)
telegram/app/qml/AccountPage.qml (+4/-0)
telegram/app/qml/AccountSendMessage.qml (+7/-0)
telegram/app/qml/AccountSettings.qml (+4/-0)
telegram/app/qml/AuthCountriesPage.qml (+2/-0)
telegram/app/qml/AuthNumberPage.qml (+3/-0)
telegram/app/qml/ProfilePage.qml (+14/-0)
telegram/app/qml/components/AccountPanel.qml (+4/-0)
telegram/app/qml/components/AttachPanel.qml (+4/-0)
telegram/app/qml/components/MediaImport.qml (+2/-0)
telegram/app/qml/components/MessageStatus.qml (+1/-0)
telegram/app/qml/components/MessagesListItem.qml (+3/-0)
telegram/app/qml/telegram.qml (+1/-0)
telegram/autopilot/CLI/test_receive_response.lua (+149/-0)
telegram/autopilot/telegram/common/__init__.py (+36/-0)
telegram/autopilot/telegram/common/config.py (+350/-0)
telegram/autopilot/telegram/common/options.py (+37/-0)
telegram/autopilot/telegram/common/ssh.py (+199/-0)
telegram/autopilot/telegram/common/utils.py (+87/-0)
telegram/autopilot/telegram/emulators.py (+550/-0)
telegram/autopilot/telegram/setup.py (+57/-0)
telegram/autopilot/telegram/tests/__init__.py (+76/-0)
telegram/autopilot/telegram/tests/test_Logout.py (+52/-0)
telegram/autopilot/telegram/tests/test_MessageDisplay.py (+205/-0)
telegram/autopilot/telegram/tests/test_Messaging.py (+402/-0)
telegram/autopilot/telegram/tests/test_Offline.py (+54/-0)
telegram/autopilot/telegram/tests/test_Profile.py (+186/-0)
telegram/autopilot/telegram/utilities.py (+36/-0)
To merge this branch: bzr merge lp:~cellsoftware/telegram-app/autopilotTest-4
Reviewer Review Type Date Requested Status
Jin (community) Approve
Roberto Mier Escandon (community) Approve
Review via email: mp+310414@code.launchpad.net

Description of the change

Autopilot tests added
Code changes involve adding 'objectName' attribute to necessary components in order to make them visible to autopilot
Build script updates (setup.sh and click.sh) to include new flag (-u) to include autopilot tests in click package for mobile build
README document updated with autopilot use

To post a comment you must log in.
Revision history for this message
Roberto Mier Escandon (rmescandon) wrote :

Please, fix conflicts "Text conflict in telegram/app/qml/components/MessagesListItem.qml"

review: Needs Fixing
246. By Paz Chauhan

Removal of parseText function

Revision history for this message
Paz Chauhan (paz-chauhan) wrote :

Conflicts hopefully resolved

Revision history for this message
Roberto Mier Escandon (rmescandon) wrote :

Still seen conflicts here. See just below the "Diff against target" section

review: Needs Fixing
247. By Paz Chauhan

conflicts resolved

248. By Paz Chauhan

.po and .pot files reverted

Revision history for this message
Roberto Mier Escandon (rmescandon) wrote :

Please revert also the telegram/po complete directory

review: Needs Fixing
249. By Paz Chauhan

.po and .pot files reverted

Revision history for this message
Roberto Mier Escandon (rmescandon) wrote :

Just a pair of commented out lines that I'm not sure if are there left on purpose. If not remove them, please

review: Needs Fixing
250. By Paz Chauhan

Commented out code explained

Revision history for this message
Roberto Mier Escandon (rmescandon) wrote :

My experience is that on device some of the tests pass, some others not. I have not been able to pass all them ever.
In desktop version, the textbox to write messages is disabled (I see also app in "waiting for network", so seem it is related) and thus the tests are not passing (send messages cannot be executed)

I guess all this can be fixed in a later MR. For now +1

review: Approve
Revision history for this message
Jin (jindallo) wrote :

I can't get them all passed as well,
no further actions on Contact selection page in running oftenly,
now the DUT from me is Nexus 4 with stable channel,
still need to verify it on BQ phone later,
will report my running result here.

Revision history for this message
Jin (jindallo) wrote :

After .lua configured now the test cases can run well,
I approve.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README.md'
2--- README.md 2016-09-30 05:22:00 +0000
3+++ README.md 2016-11-14 11:39:33 +0000
4@@ -1,4 +1,4 @@
5-# Telegram for Ubuntu
6+# **Telegram for Ubuntu**
7
8 ### TLDR;
9 "./setup.sh -t mobile -dbc" for a full mobile build
10@@ -7,60 +7,216 @@
11 ### How to build
12
13 This build setup has been tested on:
14-- Ubuntu Xenial 16.04
15+- Ubuntu Vivid 15.04 with Overlay PPA enabled
16
17 The following instructions assume you downloaded Telegram for Ubuntu source and changed ("cd") to the project's root directory.
18
19-1) Install build dependencies
20- If you're building for mobile devices:
21- If you don't have a 15.04 click chroot yet:
22- sudo click chroot --arch armhf --framework ubuntu-sdk-15.04 create
23- To install the build dependencies in the chroot:
24- sudo click chroot --arch armhf --framework ubuntu-sdk-15.04 maint
25- apt-get install libthumbnailer-qt-dev:armhf thumbnailer-service:armhf
26- Else if you're building for desktop, install the build dependencies using the following command:
27- sudo apt-get install libthumbnailer-qt-dev qml-module-ubuntu-connectivity qtdeclarative5-ubuntu-contacts0.1
28-
29-2) Environment setup
30- Change your directory into below:
31- ~/.config/QtProject/qtcreator/ubuntu-sdk/ubuntu-sdk-15.04-armhf
32- then make a symbolic link bewteen qtc_chroot_wrapper and the make:
33- ln -s /usr/share/qtcreator/ubuntu/scripts/qtc_chroot_wrapper.py make
34-
35-3) Download and build the source of libqtelegram-aseman-edition library and TelegramQML plugin:
36- - Run ./setup.sh -t <build_type> -d
37-
38- The help command will show the available values for <build_type>.
39- It'll git clone both projects to the deps directory and build them (inside the click chroot, if
40- the build type chosen was "mobile").
41- You can use same command to re-build, if you have changed them, too.
42- NOTE: it may be required to modify some environment variables that drive the build process, such
43+## **Install build dependencies**
44+### Device
45+ If you don't have a 15.04 click chroot yet:
46+
47+ $ sudo click chroot --arch armhf --framework ubuntu-sdk-15.04 create
48+
49+To install the build dependencies in the chroot:
50+
51+ $ sudo click chroot --arch armhf --framework ubuntu-sdk-15.04 maint
52+
53+ $ apt-get install libthumbnailer-qt-dev:armhf libthumbnailer-qt1.0:armhf thumbnailer-service:armhf
54+
55+### Desktop
56+
57+ Install the build dependencies using the following command:
58+
59+ $ sudo apt-get install libthumbnailer-qt-dev libthumbnailer-qt1.0 thumbnailer-service libqt5xmlpatterns5-dev qtdeclarative5-dev qtmultimedia5-dev libssl-dev
60+
61+2) Download and build the source of libqtelegram-aseman-edition library and TelegramQML plugin:
62+
63+ $ ./setup.sh -t <build_type> -d
64+
65+The help command will show the available values for <build_type>.
66+ It'll git clone both projects to the deps directory and build them (inside the click chroot, if the build type chosen was "mobile").
67+You can use same command to re-build, if you have changed them, too.
68+
69+ NOTE: it may be required to modify some environment variables that drive the build process, such
70 as the path to qmake or make, the path to system libraries, the name of the chroot, etc.
71 The env variables are grouped at the beginning of setup.sh, to make the customization easier.
72
73-4) Build Telegram for Ubuntu
74- - Run ./setup.sh -t <build_type> -b
75+3) Build Telegram for Ubuntu
76+
77+ $ ./setup.sh -t <build_type> -b
78
79- This will build the app in the build path defined by setup.sh
80+ This will build the app in the build path defined by setup.sh
81 and prepare everything in a directory named click in the project's root directory.
82 NOTE: it may be required to modify some environment variables that drive the build process, such
83 as the path to qmake or make, the path to system libraries, the name of the chroot, etc.
84 The env variables are grouped at the beginning of setup.sh, to make the customization easier.
85
86-5) (Optional) Build the click package and install it using adb (requires an Ubuntu Touch
87+4) (Optional) Build the click package and install it using adb (requires an Ubuntu Touch
88 mobile device connected via USB with developer mode enabled):
89- - Run ./setup.sh -t mobile -c
90
91+ $ ./setup.sh -t mobile -c
92
93 ### How to run (DESKTOP VERSION only)
94
95-- cd to the path holding the binary we have just build, e.g. "cd build_desktop/lib/x86_64-linux-gnu/bin/"
96-- run "LD_LIBRARY_PATH=../../../:$LD_LIBRARY_PATH ./telegram"
97+cd to the path holding the binary we have just build, e.g. `$ cd build_desktop/lib/x86_64-linux-gnu/bin/`
98+
99+ $ LD_LIBRARY_PATH=../../../:$LD_LIBRARY_PATH ./telegram
100+
101
102 ### How to delete the build files
103
104-- Run ./setup -t <build_type> -e
105+ $ ./setup -t <build_type> -e
106
107 ### How to get help
108
109-- Run ./setup -h
110+ $ ./setup -h
111+
112+----------
113+
114+# **Autopilot**
115+
116+### Install On Desktop
117+To install Autopilot on a Ubuntu Desktop follow [this tutorial](https://developer.ubuntu.com/api/autopilot/python/1.5.0/guides-installation/).
118+
119+### Install on Device
120+To install on a Ubuntu device you will need to first connect to the device via SSH:
121+
122+ $ adb shell
123+
124+Then execute the following commands:
125+
126+ $ sudo mount -o remount,rw /
127+
128+ $ sudo apt-get update
129+
130+ $ sudo apt-get install python3-autopilot ubuntu-ui-toolkit-autopilot -yq
131+
132+## **Telegram-App code changes**
133+Download the following telegram-app sample project which contains the autopilot test cases and and supporting documentation such as, **Telegram-App_Code_Changes.pdf**:
134+
135+ $ bzr branch lp:~cellsoftware/telegram-app/autopilotTest-3
136+
137+**Telegram-App_Code_Changes.pdf** lists the components which need to be updated, on your on version of the telegram-app code, with the *objectName* attribute in order for them to become visible to autopilot. This document also describes certain code changes which need to be made in order for desktop tests to pass. These are mainly to do with simulating an online device.
138+
139+Once downloaded, you will have created and autopilotTest-3 directory on your computer. The autopilot test scripts for **telegram-app** can be found in the following relative directory path:
140+
141+> autopilotTest-3/telegram/autopilot/telegram
142+
143+**This directory structure must be maintained when copying the autopilot test cases to your own version of the app.**
144+
145+##**Test Environment**
146+
147+###Telegram-CLI
148+All tests involving the sending and receiving of messages will involve the Telegram CLI. This can be downloaded from [GitHub](https://github.com/vysheng/tg). Follow the instructions to install and build. The Telegram CLI scripts are written in Lua and can be found in the following relative directory path:
149+
150+> autopilotTest-3/telegram/autopilot/CLI
151+
152+**This directory structure must be maintained when copying the autopilot test cases to your own version of the app.**
153+
154+#### Telegram CLI Launch
155+
156+Once downloaded cd, to the '**tg**' folder. Then execute the following command:
157+
158+ $ bin/telegram-cli -k tg-server.pub -W -s <location of the test script>
159+
160+###Test Data
161+The following are prerequisites to executing the autopilot test cases:
162+
163+> - A Telegram user must be logged into the app
164+> - The Telegram user must be signed into their Ubuntu One account
165+> - The app must not be launched
166+> - The device must not be screen or SIM locked
167+> - The device must be on the screen displaying the apps
168+> - The user must have 2 Telegram contacts defined, one of which must be the phone number used to set up the Telegram CLI
169+> - The Telegram CLI must be online
170+
171+## **Execution**
172+
173+### Desktop
174+
175+Before running, the **telegram-app** and its dependencies have to be built.
176+From the autopilotTest-3 directory execute the following command:
177+
178+ $ ./setup.sh -t desktop -db
179+
180+To execute the entire test suite perform the following command from the `autopilotTest-3/telegram/autopilot/` directory:
181+
182+ $ autopilot3 run telegram/
183+
184+To get a list of all individual test cases execute the following command:
185+
186+ $ autopilot3 list telegram/
187+
188+You will see an output similar to this:
189+
190+> *2 telegram.tests.test_Messaging.SecretMessaging.test_SecretMessage
191+> telegram.tests.test_Profile.ProfileTests.test_check_group_to_verify_members
192+> telegram.tests.test_Profile.ProfileDetails.test_verify_profile_details
193+> telegram.tests.test_Profile.ProfileTests.test_check_blocked_user
194+
195+The *2 next to a test case refers to the number of scenarios within that test case. Therefore executing test_SecretMessage will run the same Secret Message test case but for 2 scenarios, e.g. sending a Secret Message containing text only and sending a Secret Message containing images only.
196+
197+To execute all Profile tests execute the following:
198+
199+ $ autopilot3 run telegram.tests.test_Profile
200+
201+To execute all Profile Detail tests, execute the following:
202+
203+ $ autopilot3 run telegram.tests.test_Profile.ProfileDetails
204+
205+To execute individual tests choose a test from the list, for example *telegram.tests.test_Login.Login.test_sign_in* then execute the following command:
206+
207+ $ autopilot3 run telegram.tests.test_Login.Login.test_sign_in
208+
209+### Device
210+
211+To execute the autopilot test cases on a device, the **telegram-app**, its dependencies and the click package have to be built and installed on the device. Once you have connected your device via USB, build the mobile version of the app using the following command:
212+
213+ $ ./setup.sh -t mobile -dbcu
214+
215+Next, navigate to the installed test suite using:
216+
217+ $ adb shell
218+
219+ $ cd /opt/click.ubuntu.com/com.ubuntu.telegram/current/autopilot
220+
221+The listing and executing of tests are as described in the Desktop section.
222+
223+## **Notes**
224+After getting Autopilot working. Here are some notes you need to do to ensure tests can be run properly:
225+
226+### Device
227+
228+During device testing the orientation should remain as portrait. Changing the orientation to landscape will cause tests to fail.
229+
230+### Telegram CLI
231+
232+If any of the test cases executed require the sending and/or receiving of messages the Telegram CLI will have to be launched, as described above. If left running for some time without activity the Telegram CLI will go offline. This may cause some autopilot tests to fail. To bring the Telegram CLI back online you can issue a CLI command, or quit the CLI by entering 'safe_quit' and relaunching.
233+
234+### Flags
235+
236+Here are the types and meanings for each flag:
237+
238+**-d** - Dependency - Build the dependency to support the app
239+**-b** - Build - Builds and compile the app.
240+**-c** - Install on device
241+**-u** - Adds the autopilot tests to the click package installed on the device
242+
243+ $ ./setup.sh -t mobile -<flag(s)>
244+For a more in-depth 'how-to' see [here](https://developer.ubuntu.com/api/autopilot/python/1.5.0/guides-running_ap/).
245+
246+###Messaging
247+To get messaging working correctly you need to make some code changes in
248+AccountSendMessage.qml:
249+
250+> 1. Enable TextArea - #155 - Change to `enabled: true`.
251+> 2. Enable Sticker button (if required) - #264 - Remove `connected || !NetworkingStatus` IF statement so you only have `if
252+> (!privates.emojiItem) {...}` in `onClicked:`.
253+> 3. Enable Send button - #326 - Remove `connected || !NetworkingStatus` IF statement so you only have `if (state == “attach”) {...}` in
254+> `onClicked:`.
255+
256+## **References & Tutorials**
257+- [Autopilot Tutorials and Guides](https://developer.ubuntu.com/api/autopilot/python/1.5.0/)
258+- [Autopilot at a glance](http://www.theorangenotebook.com/2012/11/a-glance-at-autopilot.html)
259+- [Getting started with Autopilot](http://www.theorangenotebook.com/2012/11/getting-started-with-autopilot.html)
260+- [Your first autopilot test case](http://www.theorangenotebook.com/2012/11/our-first-autopilot-testcase.html)
261
262=== added file 'Telegram-App_Code_Changes.pdf'
263Binary files Telegram-App_Code_Changes.pdf 1970-01-01 00:00:00 +0000 and Telegram-App_Code_Changes.pdf 2016-11-14 11:39:33 +0000 differ
264=== modified file 'buildScripts/click.sh'
265--- buildScripts/click.sh 2015-11-02 15:30:52 +0000
266+++ buildScripts/click.sh 2016-11-14 11:39:33 +0000
267@@ -6,6 +6,16 @@
268 exit 1
269 fi
270
271+if [ "$TEST_STEP" = "y" ]; then
272+ # Copy autopilot tests into click directory
273+ echo "Removing old autopilot tests..."
274+ rm -rf $TG_DIR/$BUILD_DIR_BASENAME/click/$AUTOPILOT_DIR || exit 1
275+ echo "Adding autopilot tests to the click package..."
276+ mkdir $TG_DIR/$BUILD_DIR_BASENAME/click/$AUTOPILOT_DIR || exit 1
277+ # mkdir $TG_DIR/$BUILD_DIR_BASENAME/click/$AUTOPILOT_DIR_BASENAME || exit 1
278+ cp -avr $TG_DIR/$AUTOPILOT_PATH $TG_DIR/$BUILD_DIR_BASENAME/click/$AUTOPILOT_DIR_BASENAME || exit 1
279+fi
280+
281 cd $TG_DIR/$BUILD_DIR_BASENAME/ || exit 1
282 click build click || exit 1
283
284
285=== modified file 'setup.sh'
286--- setup.sh 2016-04-01 08:44:31 +0000
287+++ setup.sh 2016-11-14 11:39:33 +0000
288@@ -37,6 +37,10 @@
289 export SYSTEM_LIB_PATH=/usr/lib/arm-linux-gnueabihf
290 export SYSTEM_INCLUDE_PATH=/usr/include/
291 export BUILD_DIR_BASENAME=build_mobile
292+ export AUTOPILOT_DIR=autopilot
293+ export AUTOPILOT_APP_DIR=/telegram
294+ export AUTOPILOT_DIR_BASENAME=$AUTOPILOT_DIR/$AUTOPILOT_APP_DIR
295+ export AUTOPILOT_PATH=telegram/$AUTOPILOT_DIR_BASENAME
296 }
297 #Generic env vars
298 function setTelegramEnvVars() {
299@@ -65,6 +69,7 @@
300 APP_STEP=n
301 CLICK_STEP=n
302 ERASE_STEP=n
303+export TEST_STEP=n
304 RESET_ENV_VARS=n
305
306 function usage() {
307@@ -75,9 +80,10 @@
308 echo "-b To build the telegram app."
309 echo "-c To create and install the click package (only valid if mobile build type has been selected)"
310 echo "-e To erase all build files relative to the specified build type."
311+ echo "-u To include all autopilot unit test cases in the click package (only valid if -c has been selected)."
312 }
313
314-while getopts "t:dbceh" opt; do
315+while getopts "t:dbceuh" opt; do
316 case $opt in
317 t)
318 case $OPTARG in
319@@ -106,6 +112,9 @@
320 e)
321 ERASE_STEP=y
322 ;;
323+ u)
324+ TEST_STEP=y
325+ ;;
326 v)
327 RESET_ENV_VARS=y
328 ;;
329@@ -125,6 +134,12 @@
330 exit 1
331 fi
332
333+if [ "$CLICK_STEP" = "n" ] && [ "$TEST_STEP" = "y" ]; then
334+ echo "The inclusion of autopilot test cases requires the -c flag."
335+ usage
336+ exit 1
337+fi
338+
339 if [ "$BUILD_TYPE" = "desktop" ]; then
340 setDesktopBuildEnvVars
341 else
342@@ -167,3 +182,4 @@
343 if [ "$ERASE_STEP" = "y" ]; then
344 source ./buildScripts/clean.sh || exit 1
345 fi
346+
347
348=== modified file 'telegram/app/qml/AccountContactsPage.qml'
349--- telegram/app/qml/AccountContactsPage.qml 2016-06-17 15:19:54 +0000
350+++ telegram/app/qml/AccountContactsPage.qml 2016-11-14 11:39:33 +0000
351@@ -17,7 +17,7 @@
352 Page {
353 id: page
354 flickable: null
355-
356+ objectName: "accountContactsPage"
357 header: default_header
358
359 PageHeader {
360@@ -113,6 +113,7 @@
361 property var none: []
362 property list<Action> confirm: [
363 Action {
364+ objectName: "createGroupChatOK"
365 iconName: "ok"
366 text: i18n.tr("OK")
367 enabled: hasGroupTitle
368@@ -225,6 +226,7 @@
369
370 TextField {
371 id: group_chat_title_text_field
372+ objectName: "groupChatTextField"
373 anchors {
374 top: page.header.bottom
375 topMargin: isVisible ? units.gu(1) : 0
376@@ -253,6 +255,7 @@
377 }
378
379 MultipleSelectionListView {
380+ objectName: "contactList"
381 id: contact_list
382 anchors {
383 top: group_chat_title_text_field.visible ? group_chat_title_text_field.bottom : parent.top
384@@ -278,6 +281,7 @@
385
386 listModel: searchTerm == "" ? contacts_model : contacts_filter_model
387 listDelegate: TelegramContactsListItem {
388+ objectName: "contact%1".arg(index)
389 id: delegate
390 telegram: page.telegram
391 user: model.user
392
393=== modified file 'telegram/app/qml/AccountDialogList.qml'
394--- telegram/app/qml/AccountDialogList.qml 2016-07-19 15:15:28 +0000
395+++ telegram/app/qml/AccountDialogList.qml 2016-11-14 11:39:33 +0000
396@@ -57,6 +57,7 @@
397
398 ListView {
399 id: dialog_list
400+ objectName: "dialogListView"
401 anchors {
402 top: parent.top
403 left: parent.left
404@@ -81,6 +82,7 @@
405
406 delegate: DialogsListItem {
407 id: list_item
408+ objectName: "dialog%1".arg(index)
409 anchors {
410 topMargin: units.dp(3)
411 leftMargin: units.dp(5)
412
413=== modified file 'telegram/app/qml/AccountDialogPage.qml'
414--- telegram/app/qml/AccountDialogPage.qml 2016-07-22 06:27:59 +0000
415+++ telegram/app/qml/AccountDialogPage.qml 2016-11-14 11:39:33 +0000
416@@ -28,6 +28,7 @@
417
418 property list<Action> defaultActions: [
419 Action {
420+ objectName: "groupInfo"
421 iconName: "stock_contact"
422 text: isChat ? i18n.tr("Group Info") : i18n.tr("Profile Info")
423 onTriggered: {
424@@ -85,6 +86,7 @@
425 trailingActionBar.actions: message_list.inSelectionMode ? selectionActions : defaultActions
426 leadingActionBar.actions: Action {
427 id: back_action
428+ objectName: "dialogBack"
429 iconName: message_list.inSelectionMode ? "close" : "back"
430 onTriggered: {
431 if (message_list.inSelectionMode) {
432@@ -213,6 +215,7 @@
433
434 AccountSendMessage {
435 id: send_msg
436+ objectName: "accountSendMessageArea"
437 anchors {
438 right: parent.right
439 bottom: parent.bottom
440@@ -236,6 +239,7 @@
441
442 AccountMessageList {
443 id: message_list
444+ objectName: "accountMessageList"
445 anchors {
446 top: add_contact_header.visible ? add_contact_header.bottom : parent.top
447 right: parent.right
448
449=== modified file 'telegram/app/qml/AccountMessageList.qml'
450--- telegram/app/qml/AccountMessageList.qml 2016-11-14 02:59:38 +0000
451+++ telegram/app/qml/AccountMessageList.qml 2016-11-14 11:39:33 +0000
452@@ -176,6 +176,7 @@
453
454 MultipleSelectionListView {
455 id: mlist
456+ objectName: "messagesListView"
457 anchors.fill: parent
458 cacheBuffer: units.gu(10) * 20
459 clip: true
460@@ -228,6 +229,7 @@
461 listModel: messages_model
462 listDelegate: MessagesListItem {
463 id: message_item
464+ objectName: "message%1".arg(index)
465 maximumMediaHeight: acc_msg_list.maximumMediaHeight
466 maximumMediaWidth: acc_msg_list.maximumMediaWidth
467 message: item
468
469=== modified file 'telegram/app/qml/AccountMessageMedia.qml'
470--- telegram/app/qml/AccountMessageMedia.qml 2016-09-28 18:34:44 +0000
471+++ telegram/app/qml/AccountMessageMedia.qml 2016-11-14 11:39:33 +0000
472@@ -315,6 +315,7 @@
473
474 MessageStatus {
475 id: message_status
476+ objectName: "mediaMessageStatus"
477 anchors {
478 bottom: parent.bottom
479 bottomMargin: units.dp(4)
480
481=== modified file 'telegram/app/qml/AccountPage.qml'
482--- telegram/app/qml/AccountPage.qml 2016-07-11 16:11:59 +0000
483+++ telegram/app/qml/AccountPage.qml 2016-11-14 11:39:33 +0000
484@@ -75,6 +75,7 @@
485
486 AccountPanel {
487 id: account_panel
488+ objectName:"accountPanel"
489 anchors {
490 left: parent.left
491 top: parent.top
492@@ -168,6 +169,7 @@
493
494 AccountDialogList {
495 id: dialogs
496+ objectName: "accountDialogList"
497 anchors{
498 fill: parent
499 topMargin: account_page.header.height
500@@ -289,6 +291,7 @@
501 header: default_header
502 PageHeader {
503 id: default_header
504+ objectName: "defaultHeader"
505 visible: account_page.header === default_header
506 title: {
507 if (NetworkingStatus.online) {
508@@ -305,6 +308,7 @@
509 }
510 }
511 leadingActionBar.actions: Action {
512+ objectName: "navigationMenu"
513 iconName: "navigation-menu"
514 onTriggered: {
515 account_panel.opened ? account_panel.close() : account_panel.open()
516
517=== modified file 'telegram/app/qml/AccountSendMessage.qml'
518--- telegram/app/qml/AccountSendMessage.qml 2016-04-22 10:35:16 +0000
519+++ telegram/app/qml/AccountSendMessage.qml 2016-11-14 11:39:33 +0000
520@@ -139,6 +139,7 @@
521
522 TextArea {
523 id: txt
524+ objectName: "sendMessageTextArea"
525
526 property int oldLength: 0
527
528@@ -152,6 +153,9 @@
529
530 // This value is to avoid letter and underline being cut off.
531 height: units.gu(4.3)
532+
533+ // To work on desktop change the following line to:
534+ // enabled: True
535 enabled: NetworkingStatus.online && telegramObject.connected
536 visible: !messagePlaceholder.visible
537 // TRANSLATORS: Placeholder for the message input text area.
538@@ -297,6 +301,7 @@
539
540 MouseArea {
541 id: send_mouse_area
542+ objectName: "sendMouseArea"
543 height: parent.height
544 width: units.gu(6)
545 enabled: telegramObject.connected
546@@ -323,6 +328,8 @@
547 onClicked: {
548 Qt.inputMethod.commit();
549
550+ // To work on desktop change the following line to:
551+ // if (!telegramObject.connected) return
552 if (!telegramObject.connected || !NetworkingStatus.online) return
553
554 if (state == "attach") {
555
556=== modified file 'telegram/app/qml/AccountSettings.qml'
557--- telegram/app/qml/AccountSettings.qml 2016-07-13 09:13:36 +0000
558+++ telegram/app/qml/AccountSettings.qml 2016-11-14 11:39:33 +0000
559@@ -194,6 +194,7 @@
560 }
561
562 ListItem.Standard {
563+ objectName: "listItem_logout"
564 showDivider: true
565 text: i18n.tr("Log out") + " | " + telegram.phoneNumber
566 onClicked: PopupUtils.open(logout_dialog_component)
567@@ -282,6 +283,7 @@
568 }
569
570 ListView {
571+ objectName: "settingsList"
572 anchors {
573 topMargin: units.gu(2)
574 top: profile_image.bottom
575@@ -297,9 +299,11 @@
576 id: logout_dialog_component
577 Popup.Dialog {
578 id: logout_dialog
579+ objectName: "logoutDialog"
580 title: i18n.tr("Telegram")
581 text: i18n.tr("Are you sure you want to log out?\nAny secret chats will be lost.")
582 Button {
583+ objectName: "logoutConfirm"
584 text: i18n.tr("OK")
585 color: UbuntuColors.orange
586 onClicked: {
587
588=== modified file 'telegram/app/qml/AuthCountriesPage.qml'
589--- telegram/app/qml/AuthCountriesPage.qml 2016-06-22 09:29:10 +0000
590+++ telegram/app/qml/AuthCountriesPage.qml 2016-11-14 11:39:33 +0000
591@@ -22,6 +22,7 @@
592 property bool searchMode: false
593 Action {
594 id: searchAction
595+ objectName: "searchIcon"
596 iconName: "search";
597 text: i18n.tr("Search");
598 onTriggered:{
599@@ -48,6 +49,7 @@
600
601 TextField {
602 id: search_text_field
603+ objectName: "countryField"
604 visible: choose_header.searchMode
605 anchors {
606 right: parent ? parent.right : undefined
607
608=== modified file 'telegram/app/qml/AuthNumberPage.qml'
609--- telegram/app/qml/AuthNumberPage.qml 2016-06-23 07:07:53 +0000
610+++ telegram/app/qml/AuthNumberPage.qml 2016-11-14 11:39:33 +0000
611@@ -84,6 +84,9 @@
612 height: phone_number.height
613 anchors.horizontalCenter: parent.horizontalCenter
614 text: i18n.tr("Done")
615+
616+ // To work on desktop change the following line to:
617+ // enabled: phoneNumber.length > 0
618 enabled: isOnline && phoneNumber.length > 0
619 focus: true
620 onClicked: phone_number.accepted()
621
622=== modified file 'telegram/app/qml/ProfilePage.qml'
623--- telegram/app/qml/ProfilePage.qml 2016-06-27 09:22:33 +0000
624+++ telegram/app/qml/ProfilePage.qml 2016-11-14 11:39:33 +0000
625@@ -17,6 +17,7 @@
626 Page {
627 id: profile_page
628 title: isChat ? i18n.tr("Group Info") : i18n.tr("Contact Info")
629+ objectName: "profilePage"
630
631 property Telegram telegram
632 property Dialog dialog
633@@ -59,6 +60,12 @@
634 header: PageHeader {
635 title: profile_page.title
636 trailingActionBar.actions: isChat ? groupActions : noActions
637+ leadingActionBar.actions: Action {
638+ id: back_action
639+ objectName: "profileBack"
640+ iconName: "back"
641+ onTriggered: pageStack.removePages(profile_page);
642+ }
643 }
644
645 signal openDialog(var dialogId)
646@@ -186,6 +193,7 @@
647
648 MediaImport {
649 id: photo_importer
650+ objectName: "profileImageImport"
651 contentType: ContentType.Pictures
652
653 onMediaReceived: {
654@@ -235,6 +243,7 @@
655
656 ClickableContactImage {
657 id: profile_image
658+ objectName: "profileImage"
659 anchors {
660 top: parent.top
661 topMargin: units.gu(2) + profile_page.header.height
662@@ -388,6 +397,7 @@
663 spacing: units.dp(4)
664
665 Label {
666+ objectName: "profilePhoneNumber"
667 verticalAlignment: Text.AlignVCenter
668 horizontalAlignment: Text.AlignLeft
669 fontSize: "large"
670@@ -449,6 +459,7 @@
671 spacing: units.dp(4)
672
673 Label {
674+ objectName: "profileUserName"
675 id: username_label
676 fontSize: "large"
677 font.family: "Helvetica"
678@@ -621,6 +632,7 @@
679
680 Switch {
681 id: block_check
682+ objectName: "switchBlock"
683
684 property bool silentChecked
685 property bool override: false
686@@ -656,6 +668,7 @@
687
688 ListView {
689 id: participants_list
690+ objectName: "memberListView"
691 anchors {
692 top: blocked_row.bottom
693 topMargin: units.gu(2)
694@@ -669,6 +682,7 @@
695 model: chat_participants_model
696 delegate: TelegramContactsListItem {
697 id: contact_item
698+ objectName: "dialog%1".arg(index)
699 telegram: profile_page.telegram
700 user: telegram.user(item.userId)
701
702
703=== modified file 'telegram/app/qml/components/AccountPanel.qml'
704--- telegram/app/qml/components/AccountPanel.qml 2016-04-08 06:26:31 +0000
705+++ telegram/app/qml/components/AccountPanel.qml 2016-11-14 11:39:33 +0000
706@@ -72,6 +72,7 @@
707 }
708
709 AccountPanelItem {
710+ objectName:"groupChatItem"
711 icon: "../files/menu_newgroup.png"
712 text: i18n.tr("New Group")
713 showDivider: false
714@@ -81,6 +82,7 @@
715 }
716 }
717 AccountPanelItem {
718+ objectName:"secretChatItem"
719 icon: "../files/menu_secret.png"
720 text: i18n.tr("New Secret Chat")
721 onClicked: {
722@@ -89,6 +91,7 @@
723 }
724 }
725 AccountPanelItem {
726+ objectName:"panelContacts"
727 icon: "../files/menu_contacts.png"
728 text: i18n.tr("Contacts")
729 showDivider: false
730@@ -98,6 +101,7 @@
731 }
732 }
733 AccountPanelItem {
734+ objectName:"panelSettings"
735 icon: "../files/menu_settings.png"
736 text: i18n.tr("Settings")
737 showDivider: false
738
739=== modified file 'telegram/app/qml/components/AttachPanel.qml'
740--- telegram/app/qml/components/AttachPanel.qml 2015-10-01 14:19:18 +0000
741+++ telegram/app/qml/components/AttachPanel.qml 2016-11-14 11:39:33 +0000
742@@ -81,6 +81,7 @@
743 spacing: units.gu(2.8)
744
745 AttachPanelItem {
746+ objectName: "panelPhoto"
747 id: attach_photo_item
748 // TRANSLATORS: Used in attach menu, when sending a photo to the conversation.
749 text: i18n.tr("Photo")
750@@ -94,6 +95,7 @@
751
752 AttachPanelItem {
753 // TRANSLATORS: Used in attach menu, when sending a video to the conversation.
754+ objectName: "panelVideo"
755 text: i18n.tr("Video")
756 image: Qt.resolvedUrl("qrc:/qml/files/android/attach_video.png")
757 onClicked: {
758@@ -105,6 +107,7 @@
759
760 AttachPanelItem {
761 // TRANSLATORS: Used in attach menu, when sending a file to the conversation.
762+ objectName: "panelFile"
763 text: i18n.tr("File")
764 image: Qt.resolvedUrl("qrc:/qml/files/android/attach_file.png")
765 onClicked: {
766@@ -115,6 +118,7 @@
767 }
768
769 AttachPanelItem {
770+ objectName: "panelClose"
771 height: attach_photo_item.height
772 // TRANSLATORS: Used in attach menu, when sending a file to the conversation.
773 image: Qt.resolvedUrl("qrc:/qml/files/android/attach_hide1.png")
774
775=== modified file 'telegram/app/qml/components/MediaImport.qml'
776--- telegram/app/qml/components/MediaImport.qml 2016-04-08 06:08:04 +0000
777+++ telegram/app/qml/components/MediaImport.qml 2016-11-14 11:39:33 +0000
778@@ -40,6 +40,7 @@
779
780 Popups.PopupBase {
781 id: dialogue
782+ objectName: "mediaImportPopup"
783
784 property alias activeTransfer: signalConnections.target
785 focus: true
786@@ -49,6 +50,7 @@
787
788 ContentHub.ContentPeerPicker {
789 id: peerPicker
790+ objectName: "contentPeerPicker"
791
792 anchors.fill: parent
793 contentType: root.contentType
794
795=== modified file 'telegram/app/qml/components/MessageStatus.qml'
796--- telegram/app/qml/components/MessageStatus.qml 2016-05-11 10:18:15 +0000
797+++ telegram/app/qml/components/MessageStatus.qml 2016-11-14 11:39:33 +0000
798@@ -52,6 +52,7 @@
799
800 Image {
801 id: status_image
802+ objectName: "statusImage"
803 anchors.verticalCenter: parent.verticalCenter
804 width: units.gu(2)
805 height: width
806
807=== modified file 'telegram/app/qml/components/MessagesListItem.qml'
808--- telegram/app/qml/components/MessagesListItem.qml 2016-11-01 21:03:10 +0000
809+++ telegram/app/qml/components/MessagesListItem.qml 2016-11-14 11:39:33 +0000
810@@ -245,6 +245,7 @@
811
812 AccountMessageMedia {
813 id: message_media
814+ objectName: "accountMessageMedia"
815 message: message_item.message
816 visible: message_media.hasMedia && !uploading
817 showStatus: !hasLink
818@@ -268,6 +269,7 @@
819
820 Label {
821 id: message_text
822+ objectName: "messageText"
823
824 anchors {
825 top: parent.top
826@@ -296,6 +298,7 @@
827
828 MessageStatus {
829 id: message_status
830+ objectName: "messageStatus"
831 anchors {
832 top: message_text.bottom
833 right: parent.right
834
835=== modified file 'telegram/app/qml/telegram.qml'
836--- telegram/app/qml/telegram.qml 2016-07-19 15:15:28 +0000
837+++ telegram/app/qml/telegram.qml 2016-11-14 11:39:33 +0000
838@@ -235,6 +235,7 @@
839 }
840
841 AdaptivePageLayout {
842+ objectName: "APL"
843 id: pageStack
844
845 property bool forceSinglePage: false
846
847=== added directory 'telegram/autopilot'
848=== added directory 'telegram/autopilot/CLI'
849=== added file 'telegram/autopilot/CLI/canonical-logo.png'
850Binary files telegram/autopilot/CLI/canonical-logo.png 1970-01-01 00:00:00 +0000 and telegram/autopilot/CLI/canonical-logo.png 2016-11-14 11:39:33 +0000 differ
851=== added file 'telegram/autopilot/CLI/test_receive_response.lua'
852--- telegram/autopilot/CLI/test_receive_response.lua 1970-01-01 00:00:00 +0000
853+++ telegram/autopilot/CLI/test_receive_response.lua 2016-11-14 11:39:33 +0000
854@@ -0,0 +1,149 @@
855+function on_msg_receive (msg)
856+
857+ status_online(ok_cb, false);
858+
859+ -- Uncomment, if debugging, to see all properties of objects
860+ -- print ("Message From data...")
861+ -- getAllData(msg.from,nil)
862+ -- print ("Message To data...")
863+ -- getAllData(msg.to,nil)
864+ -- print ("Message data...")
865+ -- getAllData(msg,nil)
866+
867+ -- if (msg.media ~= nil) then
868+ -- print ("Message Media data...")
869+ -- getAllData(msg.media,nil)
870+ -- end
871+
872+ if msg.out then
873+ return
874+ end
875+
876+ if (msg.text == nil) and (msg.media == nil) then
877+ return
878+ end
879+
880+ if (msg.to.peer_type == "encr_chat") or (msg.to.peer_type == "chat") then
881+ from_name = msg.to.print_name;
882+ sleep_timer = 2;
883+ else
884+ from_name = msg.from.print_name;
885+ sleep_timer = 3;
886+ end
887+
888+ if (msg.text ~= nil) and string.find(msg.text, "INSTANT") then
889+ sleep_timer = 0;
890+ end
891+
892+ if (msg.media ~= nil) then
893+ sleep_timer = 3;
894+ end
895+
896+ if (msg.text ~= nil) then
897+
898+ -- wait for sender to run 'sending' confirmation checks
899+ sleep(sleep_timer);
900+
901+ -- mark the message as read
902+ mark_read(from_name, ok_cb, false);
903+
904+ if string.find(msg.text, "DO NOT REPLY") then
905+ return
906+ end
907+
908+ -- generate and send an image response, if asked for
909+ if string.find(msg.text, "SEND IMAGE") then
910+ image_location = (string.sub( debug.getinfo(1).source, 2, string.len(debug.getinfo(1).source) - 25 ));
911+ image_file = "canonical-logo.png";
912+ send_photo (from_name, (image_location .. image_file), ok_cb, false);
913+ else
914+ -- generate and send a text response
915+ reply = ("ReplyTo:" .. msg.text);
916+ send_msg (from_name, reply, ok_cb, false);
917+
918+ end
919+ end
920+
921+ if (msg.media ~= nil) then
922+
923+ -- wait for sender to run 'sending' confirmation checks
924+ sleep(sleep_timer);
925+
926+ mark_read(from_name, ok_cb, false);
927+ end
928+
929+
930+end
931+
932+
933+function ok_cb (extra, success, result)
934+
935+end
936+
937+
938+function on_our_id (id)
939+
940+end
941+
942+function on_secret_chat_created (peer)
943+
944+end
945+
946+function on_user_update (user)
947+
948+ -- Change status to online
949+ status_online(ok_cb, false);
950+
951+end
952+
953+function on_chat_update (user)
954+
955+ -- Change status to online
956+ status_online(ok_cb, false);
957+
958+end
959+
960+function on_get_difference_end ()
961+
962+ -- Change status to online
963+ status_online(ok_cb, false);
964+
965+end
966+
967+function on_binlog_replay_end ()
968+
969+ -- Change status to online
970+ status_online(ok_cb, false);
971+
972+end
973+
974+-- Helper Methods
975+
976+-- Sleep function to insert a delay in execution
977+function sleep(n)
978+ os.execute("sleep " .. tonumber(n))
979+end
980+
981+-- Recursive function to obtain properties of an object
982+function getAllData(t, prevData)
983+ -- if prevData == nil, start empty, otherwise start with prevData
984+ local data = prevData or {}
985+
986+ -- copy all the attributes from t
987+ for k,v in pairs(t) do
988+ data[k] = data[k] or v
989+ print(string.format("Key: %s, Value:%s", k, data[k]))
990+ end
991+
992+
993+ -- get t's metatable, or exit if not existing
994+ local mt = getmetatable(t)
995+ if type(mt)~='table' then return data end
996+
997+ -- get the __index from mt, or exit if not table
998+ local index = mt.__index
999+ if type(index)~='table' then return data end
1000+
1001+ -- include the data from index into data, recursively, and return
1002+ return getAllData(index, data)
1003+end
1004
1005=== added directory 'telegram/autopilot/telegram'
1006=== added file 'telegram/autopilot/telegram/__init__.py'
1007=== added directory 'telegram/autopilot/telegram/common'
1008=== added file 'telegram/autopilot/telegram/common/__init__.py'
1009--- telegram/autopilot/telegram/common/__init__.py 1970-01-01 00:00:00 +0000
1010+++ telegram/autopilot/telegram/common/__init__.py 2016-11-14 11:39:33 +0000
1011@@ -0,0 +1,36 @@
1012+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1013+
1014+#
1015+# Ubuntu System Tests
1016+# Copyright (C) 2016 Canonical
1017+#
1018+# This program is free software: you can redistribute it and/or modify
1019+# it under the terms of the GNU General Public License as published by
1020+# the Free Software Foundation, either version 3 of the License, or
1021+# (at your option) any later version.
1022+#
1023+# This program is distributed in the hope that it will be useful,
1024+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1025+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1026+# GNU General Public License for more details.
1027+#
1028+# You should have received a copy of the GNU General Public License
1029+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1030+#
1031+
1032+from telegram.common.utils import (
1033+ clean_dir,
1034+ delete_file,
1035+ get_random_string,
1036+ get_tests_ids_to_run,
1037+ get_tests_to_run,
1038+)
1039+
1040+
1041+__all__ = [
1042+ 'clean_dir',
1043+ 'delete_file',
1044+ 'get_random_string',
1045+ 'get_tests_ids_to_run',
1046+ 'get_tests_to_run',
1047+]
1048
1049=== added file 'telegram/autopilot/telegram/common/config.py'
1050--- telegram/autopilot/telegram/common/config.py 1970-01-01 00:00:00 +0000
1051+++ telegram/autopilot/telegram/common/config.py 2016-11-14 11:39:33 +0000
1052@@ -0,0 +1,350 @@
1053+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1054+
1055+#
1056+# Ubuntu System Tests
1057+# Copyright (C) 2014-2016 Canonical
1058+#
1059+# This program is free software: you can redistribute it and/or modify
1060+# it under the terms of the GNU General Public License as published by
1061+# the Free Software Foundation, either version 3 of the License, or
1062+# (at your option) any later version.
1063+#
1064+# This program is distributed in the hope that it will be useful,
1065+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1066+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1067+# GNU General Public License for more details.
1068+#
1069+# You should have received a copy of the GNU General Public License
1070+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1071+#
1072+
1073+import configparser
1074+import logging
1075+import os
1076+
1077+from telegram.common import options
1078+
1079+logger = logging.getLogger(__name__)
1080+config_stack = None
1081+
1082+DEFAULT_CONF = 'ubuntu-system-tests.conf'
1083+KEY_DEFAULT = 'default'
1084+
1085+
1086+CONFIG_OPTIONS = [
1087+ options.Option(
1088+ 'device_serial', help_string='Device serial'),
1089+ options.Option(
1090+ 'device_password', help_string='Device password', mandatory=True),
1091+ options.Option(
1092+ 'output_dir', mandatory=True,
1093+ help_string='Directory to store the tests results and artifacts.\n'
1094+ 'WARNING: This directory will have all existing content '
1095+ 'deleted!'),
1096+ options.Option(
1097+ 'sim_0_pin', mandatory=True,
1098+ help_string='SIM pin for the card in the first slot'),
1099+ options.Option(
1100+ 'sim_1_pin',
1101+ help_string='SIM pin for the card in the second slot'),
1102+ options.Option(
1103+ 'wifi_ssid', mandatory=True,
1104+ help_string='Wi-Fi SSID used to connect during setup wizard'),
1105+ options.Option(
1106+ 'wifi_password', mandatory=True,
1107+ help_string='Wi-Fi password used to connect during setup wizard'),
1108+ options.Option(
1109+ 'device_security', default='Passcode',
1110+ help_string='The security method to select during setup wizard'),
1111+ options.Option(
1112+ 'bluetooth_device_name',
1113+ help_string='Name of a nearby bluetooth pairing device'),
1114+ options.Option(
1115+ 'device_phone_number',
1116+ help_string="The phone number of the SIM card inserted in the first "
1117+ "SIM slot. This must be formatted exactly as you would "
1118+ "dial it."),
1119+ options.Option(
1120+ 'device_phone_number2',
1121+ help_string="The phone number of the SIM card inserted in the second "
1122+ "SIM slot. If the device has only one SIM slot, you can "
1123+ "leave this blank. This must be formatted exactly as you "
1124+ "would dial it."),
1125+ options.Option(
1126+ 'telephony_service_number1',
1127+ help_string="The phone number to call and message from "
1128+ "in the telephony service. In Twilio go to "
1129+ "https://www.twilio.com/user/account/"
1130+ "phone-numbers/incoming and click on the number "
1131+ "you want to use, then copy the 'Phone Number' "
1132+ "field exactly."),
1133+ options.Option(
1134+ 'telephony_service_number2',
1135+ help_string="The second phone number to call and message from "
1136+ "in the telephony service. In Twilio go to "
1137+ "https://www.twilio.com/user/account/"
1138+ "phone-numbers/incoming and click on the number "
1139+ "you want to use, then copy the 'Phone Number' "
1140+ "field exactly."),
1141+ options.Option(
1142+ # this is a private key, that will not be exported to
1143+ # autopilot directly
1144+ '_twilio_account_sid', mandatory=True,
1145+ help_string='Account SID for Twilio. Please log into '
1146+ 'https://www.twilio.com/login '
1147+ 'and select \'Dashboard -> Show API Credentials\'.'
1148+ 'Then copy and paste the Account SID value here.'),
1149+ options.Option(
1150+ # this is a private key, that will not be exported to
1151+ # autopilot directly
1152+ '_twilio_auth_token', mandatory=True,
1153+ help_string='Auth token for Twilio account. Please log into '
1154+ 'https://www.twilio.com/login '
1155+ 'and select \'Dashboard -> Show API Credentials\'.'
1156+ 'Then copy and paste the Auth token value here.'),
1157+ options.Option(
1158+ # this is a private key, that will not be exported to
1159+ # autopilot directly
1160+ 'max_unity8_retry_delay', default=30000,
1161+ help_string='The boundary for how long we should be retrying until '
1162+ 'unity8 is started'),
1163+ options.Option(
1164+ 'app_startup_cold_runs', default=0,
1165+ help_string='How many iterations to run for the cold start app '
1166+ 'performance tests?'),
1167+ options.Option(
1168+ 'app_startup_hot_runs', default=0,
1169+ help_string='How many iterations to run for the hot start app '
1170+ 'performance tests?'),
1171+ options.Option(
1172+ 'email_outlook', default='platform_qa_test@outlook.com',
1173+ help_string='@outlook.com email address to use for email tests'),
1174+ options.Option(
1175+ 'password_outlook', mandatory=True,
1176+ help_string='@outlook.com password to use for email tests'),
1177+ options.Option(
1178+ 'email_yahoo', default='platform_qa_test_account@yahoo.com',
1179+ help_string='@yahoo.com email address to use for email tests'),
1180+ options.Option(
1181+ 'password_yahoo', mandatory=True,
1182+ help_string='@yahoo.com password to use for email tests'),
1183+ options.Option(
1184+ 'username_imap', default='platform-qa-test-account',
1185+ help_string='IMAP username to use for email tests'),
1186+ options.Option(
1187+ 'password_imap', mandatory=True,
1188+ help_string='IMAP password to use for email tests'),
1189+ options.Option(
1190+ 'pictures_scalability_runs',
1191+ help_string='The different loads used for scalability pictures tests '
1192+ 'separated by comma'),
1193+ options.Option(
1194+ '_practitest_project_id',
1195+ help_string='Practitest project ID to use for retrieving test lists.'),
1196+ options.Option(
1197+ '_practitest_api_token',
1198+ help_string='Practitest api token used for authentication.'),
1199+ options.Option(
1200+ 'country_sim', default='United States',
1201+ help_string='The name of the country of the SIM card to use for '
1202+ 'telegram login'),
1203+]
1204+
1205+
1206+def get_user_config_dir():
1207+ """Return the path to the user configuration directory."""
1208+ conf_dir = os.environ.get(
1209+ 'XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
1210+ return conf_dir
1211+
1212+
1213+def get_device_config_file_path():
1214+ """Return the path of the config file copied to the device."""
1215+ return '/tmp/ubuntu-system-tests.conf'
1216+
1217+
1218+def get_device_config_section():
1219+ """Return the name of config section to use."""
1220+ return os.environ.get('CONFIG_SECTION')
1221+
1222+
1223+def get_config_stack_from_file(file_path, config_section=None):
1224+ """Return config stack from specified file path."""
1225+ config = UbuntuSystemTestsConfig(file_path, section=config_section)
1226+ config.get_config_from_file()
1227+ return config
1228+
1229+
1230+def get_device_config_stack():
1231+ """Return the config stack variable"""
1232+ global config_stack
1233+ if not config_stack:
1234+ config_stack = get_config_stack_from_file(
1235+ get_device_config_file_path(), get_device_config_section())
1236+ return config_stack
1237+
1238+
1239+def get_test_config_values(config_stack):
1240+ """ Return a string containing the comma separated key=value options.
1241+ The list includes the config values and the temporal ones as well
1242+ """
1243+ return config_stack.get_autopilot_config_string()
1244+
1245+
1246+class UbuntuSystemTestsConfig():
1247+
1248+ """Class to get and save test configuration data."""
1249+
1250+ def __init__(self, file_name=None, section=None, options=None):
1251+ """
1252+ Construct the config and parser object.
1253+ :param file_name: Name of config file to load. Default file is used if
1254+ value is not specified.
1255+ :param section: Name of section to use in config file. Default section
1256+ is used if not specified.
1257+ :param options: List of options that should be specified in config.
1258+ Default list of options is used if not specified.
1259+ """
1260+ user_config_dir = get_user_config_dir()
1261+ if not os.path.exists(user_config_dir):
1262+ os.mkdir(user_config_dir)
1263+ self.file_path = os.path.join(
1264+ user_config_dir, file_name or DEFAULT_CONF)
1265+ self.section = section or KEY_DEFAULT
1266+ self.parser = configparser.ConfigParser(
1267+ allow_no_value=True, empty_lines_in_values=False,
1268+ default_section=KEY_DEFAULT)
1269+ self.config = {}
1270+ self.options = options or CONFIG_OPTIONS
1271+
1272+ def set(self, option_name, value):
1273+ """Set a config value.
1274+ :param option_name: Name of config option.
1275+ :param value: Value to set.
1276+ """
1277+ self.config[option_name] = value
1278+ self.save()
1279+
1280+ def get(self, option_name, default=''):
1281+ """Get a config value.
1282+ :param option_name: Name of config option to get.
1283+ :param default: Value to return as default if item doesn't exist.
1284+ :return: Config option value if it exists. If the config option itself
1285+ doesn't exist, return None. Otherwise if the option exists but no value
1286+ is defined return the default value."""
1287+ return self.config.get(option_name, default)
1288+
1289+ def save(self):
1290+ """Save the config to file."""
1291+ mode = 'r+' if os.path.exists(self.file_path) else 'w'
1292+ with open(self.file_path, mode) as f:
1293+ self.parser.write(f)
1294+
1295+ def get_config_from_string(self, string):
1296+ """Load config from a string. This is used for selftests only.
1297+ :param string: Config string to load from.
1298+ """
1299+ self.parser.read_string(string)
1300+ self._save_config_for_section()
1301+
1302+ def get_config_from_file(self):
1303+ """Load config from file."""
1304+ self.parser.read(self.file_path)
1305+ self._save_config_for_section()
1306+
1307+ def _save_config_for_section(self):
1308+ """Save the current config for the specified section only."""
1309+ self.config = self.parser[self.section]
1310+
1311+ def get_missing_options(self, silent=False):
1312+ """Check through each required option and get a value for each one
1313+ that is not present.
1314+ :param silent: Whether to query stdin for an input value or take a
1315+ default value where it exists.
1316+ """
1317+ save_required = False
1318+ for option in self.options:
1319+ if option.name in self.config:
1320+ # name exists, check if its mandatory and if a value exists
1321+ if option.mandatory and not self.config.get(option.name):
1322+ # mandatory and no value exists, so get one
1323+ self._get_option_value(option, silent)
1324+ save_required = True
1325+ else:
1326+ # option name not in config, get a value
1327+ self._get_option_value(option, silent)
1328+ save_required = True
1329+ self._save_if_required(save_required)
1330+
1331+ def _save_if_required(self, save_required):
1332+ """Save config if it is required.
1333+ :param save_required: Whether to save or not.
1334+ """
1335+ if save_required:
1336+ self.save()
1337+
1338+ def _get_option_value(self, option, silent):
1339+ """Request a value for specified option.
1340+ :param option: Required option.
1341+ :param silent: Whether to query stdin or take default value.
1342+ """
1343+ if silent:
1344+ default = option.default
1345+ if default:
1346+ self.config[option.name] = option.default
1347+ logger.warning(
1348+ 'In silent mode no value specified for option: "{o}". '
1349+ 'Using default value "{v}".'.format(
1350+ o=option.name, v=default))
1351+ else:
1352+ logger.warning(
1353+ 'In silent mode no default value specified for option: '
1354+ '"{o}". Continuing with value unset.'.format(
1355+ o=option.name))
1356+ else:
1357+ self._get_option_value_from_stdin(option)
1358+
1359+ def _get_option_value_from_stdin(self, option):
1360+ """Request option value from stdin.
1361+ :param option: Required option.
1362+ """
1363+ help_msg = self._get_option_help_text(option)
1364+ print(help_msg, end='')
1365+ value = self._get_value_from_user_or_default(option)
1366+ self.config[option.name] = value
1367+
1368+ def _get_option_help_text(self, option):
1369+ """Return help message for specified option.
1370+ :param option: Required option.
1371+ """
1372+ help_msg = option.help_string
1373+ default = option.default
1374+ if default:
1375+ help_msg += ' (leave blank to use default value: {})'.format(
1376+ default)
1377+ elif not option.mandatory:
1378+ help_msg += ' (leave blank if not required)'
1379+ help_msg += ': '
1380+ return help_msg
1381+
1382+ def _get_value_from_user_or_default(self, option):
1383+ """Return value from stdin or default value if no stdin value."""
1384+ return input() or option.default
1385+
1386+ def get_autopilot_config_string(self):
1387+ """Return the configuration in a string usable by Autopilot.
1388+
1389+ That is, a list of key=value pairs serparated by comma.
1390+
1391+ Any keys starting with _ will be ignored.
1392+
1393+ """
1394+ config = ''
1395+ for key, value in self.config.items():
1396+ if not key.startswith('_'):
1397+ config += '{k}={v},'.format(k=key, v=value)
1398+
1399+ # remove trailing ',' if it exists
1400+ if config.endswith(','):
1401+ config = config[:-1]
1402+ return config
1403
1404=== added file 'telegram/autopilot/telegram/common/options.py'
1405--- telegram/autopilot/telegram/common/options.py 1970-01-01 00:00:00 +0000
1406+++ telegram/autopilot/telegram/common/options.py 2016-11-14 11:39:33 +0000
1407@@ -0,0 +1,37 @@
1408+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1409+
1410+#
1411+# Ubuntu System Tests
1412+# Copyright (C) 2016 Canonical
1413+#
1414+# This program is free software: you can redistribute it and/or modify
1415+# it under the terms of the GNU General Public License as published by
1416+# the Free Software Foundation, either version 3 of the License, or
1417+# (at your option) any later version.
1418+#
1419+# This program is distributed in the hope that it will be useful,
1420+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1421+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1422+# GNU General Public License for more details.
1423+#
1424+# You should have received a copy of the GNU General Public License
1425+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1426+#
1427+
1428+
1429+class Option():
1430+
1431+ """Class to represent configuration option."""
1432+
1433+ def __init__(self, name, help_string, default=None, mandatory=False):
1434+ """
1435+ Construct the Option object.
1436+ :param name: Name of option.
1437+ :param help_string: Help message to explain option to user.
1438+ :param default: Default value for option.
1439+ :param mandatory: Whether the option is mandatory or not.
1440+ """
1441+ self.name = name
1442+ self.help_string = help_string
1443+ self.default = str(default) if default else None
1444+ self.mandatory = mandatory
1445
1446=== added file 'telegram/autopilot/telegram/common/ssh.py'
1447--- telegram/autopilot/telegram/common/ssh.py 1970-01-01 00:00:00 +0000
1448+++ telegram/autopilot/telegram/common/ssh.py 2016-11-14 11:39:33 +0000
1449@@ -0,0 +1,199 @@
1450+#!/usr/bin/env python3
1451+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1452+
1453+#
1454+# Ubuntu System Tests
1455+# Copyright (C) 2015 Canonical
1456+#
1457+# This program is free software: you can redistribute it and/or modify
1458+# it under the terms of the GNU General Public License as published by
1459+# the Free Software Foundation, either version 3 of the License, or
1460+# (at your option) any later version.
1461+#
1462+# This program is distributed in the hope that it will be useful,
1463+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1464+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1465+# GNU General Public License for more details.
1466+#
1467+# You should have received a copy of the GNU General Public License
1468+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1469+#
1470+
1471+import getpass
1472+import glob
1473+import os
1474+import re
1475+import socket
1476+import stat
1477+import subprocess
1478+
1479+from ubuntu_system_tests.common import (
1480+ get_random_string,
1481+ delete_file
1482+)
1483+
1484+SSH_IP = 'SSH_IP'
1485+SSH_PASSPHRASE = 'SSH_PASSPHRASE'
1486+SSH_PRIVATE_KEY = 'SSH_PRIVATE_KEY'
1487+SSH_USER = 'SSH_USER'
1488+
1489+
1490+def get_ssh_ip_address():
1491+ """Return ssh passphrase value."""
1492+ return os.environ.get(SSH_IP)
1493+
1494+
1495+def get_ssh_passphrase():
1496+ """Return ssh passphrase value."""
1497+ return os.environ.get(SSH_PASSPHRASE)
1498+
1499+
1500+def get_ssh_private_key():
1501+ """Return path to ssh private key file."""
1502+ return os.environ.get(SSH_PRIVATE_KEY)
1503+
1504+
1505+def get_ssh_user():
1506+ """Return ssh username value."""
1507+ return os.environ.get(SSH_USER)
1508+
1509+
1510+def _get_local_ip_address():
1511+ """ Retrieve the local ip address
1512+ :return: The ip obtained from the socket connection
1513+ """
1514+ ip = '127.0.0.1'
1515+ try:
1516+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
1517+ s.connect(("8.8.8.8", 80))
1518+ ip = s.getsockname()[0]
1519+ finally:
1520+ s.close()
1521+ return ip
1522+
1523+
1524+def _get_set_env_var_command(name, value):
1525+ """Return command to set environment variable on device."""
1526+ return ['--env={n}={v}'.format(n=name, v=value)]
1527+
1528+
1529+def _get_copy_file_to_device_command(src, dest):
1530+ """Return command to copy a file to the device."""
1531+ return ['--copy', '{s}:{d}'.format(s=src, d=dest)]
1532+
1533+
1534+def get_ssh_config_commands():
1535+ """ Retrieve a private key that can be used to connect to the host and add
1536+ the public key to the authorized_keys if it is not included yet. If either
1537+ it is not required to configure ssh or the ssh password is defined,
1538+ keypairs are not used and the function return None
1539+ """
1540+ cmds = []
1541+ cmds.extend(_get_set_env_var_command(SSH_IP, _get_local_ip_address()))
1542+ cmds.extend(_get_set_env_var_command(SSH_USER, getpass.getuser()))
1543+
1544+ # Add the private key and the passphrase when it is needed
1545+ private_key = get_valid_key()
1546+ if not private_key:
1547+ private_key, public_key = generate_keypair(get_random_string(10))
1548+ add_public_key_to_ssh_uthorized_keys(public_key)
1549+ os.remove(public_key)
1550+
1551+ device_key_file = get_device_keyfile_path(private_key)
1552+ cmds.extend(_get_set_env_var_command(
1553+ SSH_PASSPHRASE, _get_key_passprhase(private_key)))
1554+ cmds.extend(_get_set_env_var_command(SSH_PRIVATE_KEY, device_key_file))
1555+ cmds.extend(_get_copy_file_to_device_command(private_key, device_key_file))
1556+ return cmds
1557+
1558+
1559+def _get_key_passprhase(private_key):
1560+ """ Get the passphrase from the name, None if it is not found """
1561+ keyname = os.path.basename(private_key)
1562+ match = re.search(r'test_(.+)_key', keyname)
1563+ if match:
1564+ return match.group(1)
1565+ else:
1566+ return
1567+
1568+
1569+def _get_ssh_authorized_keys_path():
1570+ path = os.path.join(os.path.expanduser('~'), '.ssh', 'authorized_keys')
1571+ directory = os.path.dirname(path)
1572+ if not os.path.exists(directory):
1573+ os.makedirs(directory)
1574+ if not os.path.exists(path):
1575+ file = open(path, 'w')
1576+ file.close()
1577+ return path
1578+
1579+
1580+def is_authorized_key(id):
1581+ """ Indicate if the comment it is part of the ssh authorized_keys file
1582+ :param id: a string used to identify the public key. Currently the
1583+ passphrase is being used for that
1584+ """
1585+ authorized_keys = _get_ssh_authorized_keys_path()
1586+ command_check = ['grep', '"{c}"'.format(c=id), authorized_keys]
1587+ return subprocess.call(command_check, stdout=subprocess.PIPE) == 0
1588+
1589+
1590+def add_public_key_to_ssh_uthorized_keys(public_key):
1591+ """ Add the public key to the ssh authorized_keys if is not included yet"""
1592+ # In case the public key is not authorized yet, add it to the
1593+ # authorized_keys file
1594+ authorized_keys = _get_ssh_authorized_keys_path()
1595+ command_add = 'cat {public_key} >> {authorized_keys}'.format(
1596+ public_key=public_key, authorized_keys=authorized_keys)
1597+ subprocess.call(command_add, shell=True)
1598+
1599+
1600+def get_valid_key():
1601+ """ Retrieve a private key which has its public key is already authorized
1602+ to be used through ssh
1603+ """
1604+ all_keys = get_all_defined_keys()
1605+ for key in all_keys:
1606+ passphrase = _get_key_passprhase(key)
1607+ if passphrase and is_authorized_key(passphrase):
1608+ return key
1609+ return
1610+
1611+
1612+def get_all_defined_keys():
1613+ """ Retrieve the keys already saved in the tmp dir """
1614+ return glob.glob('/tmp/test_*_key')
1615+
1616+
1617+def generate_keypair(passphrase):
1618+ """ Create a pair of keys with the passphrase as part of the key names """
1619+ keypath = '/tmp/test_{}_key'.format(passphrase)
1620+ command = 'ssh-keygen -t rsa -b 4096 -C "{p}" -P "{p}" -f {k} -q'
1621+ command = command.format(p=passphrase,
1622+ k=keypath)
1623+ subprocess.check_call(command, shell=True)
1624+ return keypath, keypath + '.pub'
1625+
1626+
1627+def get_device_keyfile_path(filepath):
1628+ """Return the path of the config file copied to the device."""
1629+ return os.path.join('/tmp', os.path.basename(filepath))
1630+
1631+
1632+def prepare_device_keys():
1633+ """ Prepare the keyfile to be used by changing the ownership and the
1634+ permissions. These changes are done when other ssh authentication
1635+ mechanisms have not being selected
1636+ """
1637+ passphrase = get_ssh_passphrase()
1638+ key_file = get_ssh_private_key()
1639+
1640+ if passphrase and key_file and os.path.isfile(key_file):
1641+ os.chown(key_file, os.getuid(), os.getgid())
1642+ os.chmod(key_file, stat.S_IREAD)
1643+
1644+
1645+def ensure_device_keyfile_deleted():
1646+ """ Delete the private key file in the device when required """
1647+ key_file = get_ssh_private_key()
1648+ not key_file or delete_file(key_file)
1649
1650=== added file 'telegram/autopilot/telegram/common/utils.py'
1651--- telegram/autopilot/telegram/common/utils.py 1970-01-01 00:00:00 +0000
1652+++ telegram/autopilot/telegram/common/utils.py 2016-11-14 11:39:33 +0000
1653@@ -0,0 +1,87 @@
1654+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1655+
1656+#
1657+# Ubuntu System Tests
1658+# Copyright (C) 2015 Canonical
1659+#
1660+# This program is free software: you can redistribute it and/or modify
1661+# it under the terms of the GNU General Public License as published by
1662+# the Free Software Foundation, either version 3 of the License, or
1663+# (at your option) any later version.
1664+#
1665+# This program is distributed in the hope that it will be useful,
1666+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1667+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1668+# GNU General Public License for more details.
1669+#
1670+# You should have received a copy of the GNU General Public License
1671+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1672+#
1673+
1674+import inspect
1675+import os
1676+import random
1677+import shutil
1678+import string
1679+
1680+
1681+def clean_dir(dir_path):
1682+ """Delete all the content of the directory"""
1683+ if os.path.isdir(dir_path):
1684+ for obj in os.listdir(dir_path):
1685+ _delete(os.path.join(dir_path, obj))
1686+
1687+
1688+def _delete(obj):
1689+ """ Delete an object which could be either a file or a dir """
1690+ if os.path.isfile(obj):
1691+ os.remove(obj)
1692+ else:
1693+ shutil.rmtree(obj, True)
1694+
1695+
1696+def delete_file(file_name):
1697+ """Delete the file passed as parameter. In case the file does not
1698+ exist, the deletion is skipped"""
1699+ if os.path.isfile(file_name):
1700+ os.unlink(file_name)
1701+
1702+
1703+def get_random_string(length=10):
1704+ """Get a string with random content"""
1705+ return ''.join(random.choice(string.ascii_uppercase) for i in
1706+ range(length))
1707+
1708+
1709+def get_tests_ids_to_run(tests_module=None, testsuite_list_filepath=None):
1710+ """Return a list of the test ids to run in the test bed.
1711+
1712+ :param tests_module: The module that contains the Ubuntu System Tests.
1713+ Default value is ubuntu_system_tests.tests. Currently, a value other
1714+ than the default is used only for self-testing.
1715+
1716+ """
1717+ tests_from_config = get_tests_to_run()
1718+ if tests_from_config:
1719+ return tests_from_config.split()
1720+
1721+ # If we do this at the module level then we need to have unity8 and UITK on
1722+ # the host and would rather avoid this
1723+ from ubuntu_system_tests import external_tests
1724+ test_ids = external_tests.get_external_test_ids(testsuite_list_filepath)
1725+
1726+ if tests_module is None:
1727+ # We delay the import so this is only executed in the test bed, not on
1728+ # the host which might have a different version of the libraries used
1729+ # in the system tests.
1730+ from ubuntu_system_tests import tests
1731+ tests_module = tests
1732+
1733+ if inspect.ismodule(tests_module):
1734+ test_ids.append(tests_module.__name__)
1735+
1736+ return test_ids
1737+
1738+
1739+def get_tests_to_run():
1740+ return os.getenv('TESTS_TO_RUN')
1741
1742=== added file 'telegram/autopilot/telegram/emulators.py'
1743--- telegram/autopilot/telegram/emulators.py 1970-01-01 00:00:00 +0000
1744+++ telegram/autopilot/telegram/emulators.py 2016-11-14 11:39:33 +0000
1745@@ -0,0 +1,550 @@
1746+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
1747+# Copyright 2016 Canonical
1748+#
1749+# This file is part of telegram-app.
1750+#
1751+# telegram-app is free software: you can redistribute it and/or modify it
1752+# under the terms of the GNU General Public License version 3, as published
1753+# by the Free Software Foundation.
1754+
1755+
1756+"""Telegram app autopilot emulators."""
1757+
1758+from autopilot import logging as autopilot_logging
1759+from autopilot.introspection.dbus import StateNotFoundError
1760+from autopilot.utilities import sleep
1761+from autopilot import platform
1762+
1763+from ubuntuuitoolkit import emulators as toolkit_emulators
1764+from ubuntuuitoolkit._custom_proxy_objects import _common
1765+from ubuntuuitoolkit._custom_proxy_objects._common import is_maliit_process_running
1766+#from ubuntu_keyboard.emulators.keyboard import Keyboard as UbuntuKeyboard
1767+#from address_book_app import address_book
1768+
1769+from telegram import utilities
1770+
1771+import logging
1772+import time
1773+import dbus
1774+
1775+# from telegram.helpers.notifications.utils import Notifications
1776+
1777+
1778+#logger = logging.getLogger(__name__)
1779+class MainView(toolkit_emulators.MainView):
1780+
1781+ def __init__(self, *args):
1782+ super(MainView, self).__init__(*args)
1783+ self.pointing_device = toolkit_emulators.get_pointing_device()
1784+ self._account_page = None
1785+ self._apl = None
1786+ self._content_hub_popup = None
1787+ self._content_picker = None
1788+ self._content_hub_app_gallery = None
1789+ self._confirmation_dialog = None
1790+
1791+ @property
1792+ def account_page(self):
1793+ if self._account_page is None:
1794+ try:
1795+ self._account_page = self.wait_select_single(AccountPage, objectName="accountPage", active=True)
1796+ except StateNotFoundError:
1797+ raise RuntimeError("User needs to be logged on")
1798+ return self._account_page
1799+
1800+ @property
1801+ def apl(self):
1802+ if self._apl is None:
1803+ self._apl = self.wait_select_single(AdaptivePageLayout, objectName="APL", active=True)
1804+ return self._apl
1805+
1806+ @property
1807+ def content_picker(self):
1808+ if self._content_hub_popup is None:
1809+ self._content_hub_popup = self.wait_select_single(objectName="mediaImportPopup")
1810+ self._content_picker = self._content_hub_popup.wait_select_single(objectName="contentPeerPicker")
1811+ return self._content_picker
1812+
1813+ def select_content_hub_app(self, appName):
1814+ cp = self.content_picker
1815+ content_hub_gridviews = cp.select_many(objectName="responsiveGridViewGrid")
1816+ for gridview in content_hub_gridviews:
1817+ app_icon_labels = gridview.select_many(objectName="label")
1818+ if len(app_icon_labels) > 0:
1819+ for app_icon_label in app_icon_labels:
1820+ if appName in app_icon_label.text:
1821+ self.pointing_device.click_object(app_icon_label)
1822+ return
1823+
1824+ @property
1825+ def confirmation_dialog(self):
1826+ if self._confirmation_dialog is None:
1827+ self._confirmation_dialog = self.wait_select_single(Dialog, objectName='confirmationDialog')
1828+ return self._confirmation_dialog
1829+
1830+ def click_header_action(self, action):
1831+ """Click the action 'action' on the header"""
1832+ action = self.wait_select_single(objectName='%s_button' % action)
1833+ self.pointing_device.click_object(action)
1834+
1835+ # def get_notifications_list(self):
1836+ # """Return a list of notifications currently being displayed."""
1837+ # return self.wait_select_single(Notifications, objectName='notificationList')
1838+
1839+
1840+class AdaptivePageLayout(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
1841+
1842+ def __init__(self, *args):
1843+ super(AdaptivePageLayout, self).__init__(*args)
1844+ self._intro_page = None
1845+ self._contacts_page = None
1846+ self._dialog_page = None
1847+ self._settings_page = None
1848+ self._profile_page = None
1849+ self._countries_page = None
1850+ self._auth_phone_page = None
1851+ self._auth_code_page = None
1852+
1853+ @property
1854+ def intro_page(self):
1855+ if self._intro_page is None:
1856+ try:
1857+ self._intro_page = self.wait_select_single(IntroPage, objectName='introPage', active=True)
1858+ except StateNotFoundError:
1859+ raise RuntimeError("Intro page is not active")
1860+ return self._intro_page
1861+
1862+ @property
1863+ def countries_page(self):
1864+ if self._countries_page is None:
1865+ self._countries_page = self.wait_select_single(AuthCountriesPage, objectName='countriesListPage', active=True)
1866+ return self._countries_page
1867+
1868+ @property
1869+ def auth_phone_page(self):
1870+ if self._auth_phone_page is None:
1871+ self._auth_phone_page = self.wait_select_single(AuthNumberPage, objectName='authPhonePage', active=True)
1872+ return self._auth_phone_page
1873+
1874+ @property
1875+ def auth_code_page(self):
1876+ if self._auth_code_page is None:
1877+ self._auth_code_page = self.wait_select_single(AuthCodePage, objectName='authCodePage', active=True)
1878+ return self._auth_code_page
1879+
1880+ @property
1881+ def contacts_page(self):
1882+ if self._contacts_page is None:
1883+ self._contacts_page = self.wait_select_single(AccountContactsPage, objectName='accountContactsPage', active=True)
1884+ return self._contacts_page
1885+
1886+ @property
1887+ def dialog_page(self):
1888+ if self._dialog_page is None:
1889+ self._dialog_page = self.wait_select_single(AccountDialogPage, objectName='dialogPage', active=True)
1890+ return self._dialog_page
1891+
1892+ @property
1893+ def settings_page(self):
1894+ if self._settings_page is None:
1895+ self._settings_page = self.wait_select_single(AccountSettings, objectName="settingsPage", active=True)
1896+ return self._settings_page
1897+
1898+ @property
1899+ def profile_page(self):
1900+ if self._profile_page is None:
1901+ self._profile_page = self.wait_select_single(ProfilePage, objectName="profilePage", active=True)
1902+ return self._profile_page
1903+
1904+ def clear_profile_page(self):
1905+ self._profile_page = None
1906+
1907+
1908+class IntroPage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
1909+ def __init__(self, *args):
1910+ super(IntroPage, self).__init__(*args)
1911+
1912+ def press_start_messaging(self):
1913+ return self.pointing_device.click_object(self.wait_select_single(objectName="startMessagingButton"))
1914+
1915+class AccountPage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
1916+
1917+ def open_account_panel(self):
1918+ self.click_action_button('navigationMenu')
1919+ account_panel = self.wait_select_single(AccountPanel, objectName='accountPanel')
1920+ account_panel.visible.wait_for(True)
1921+ return account_panel
1922+
1923+ def get_mainview_header(self):
1924+ """Return the Header custom proxy object of the Page."""
1925+ return self.get_root_instance().wait_select_single('MainView').get_header()
1926+
1927+ def get_default_header(self):
1928+ try:
1929+ return self.wait_select_single('PageHeader', objectName='defaultHeader')
1930+ except:
1931+ raise RuntimeError('The Account Page has no header.')
1932+
1933+ def click_action_button(self, action_name):
1934+ action = self.wait_select_single(objectName='%s_button' % action_name)
1935+ self.pointing_device.click_object(action)
1936+
1937+ def get_dialog_list_page(self):
1938+ return self.wait_select_single(AccountDialogList, objectName='accountDialogList')
1939+
1940+
1941+class AccountPanel(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
1942+
1943+ def get_account_panel_list(self):
1944+ return self.wait_select_single('AccountPanel', objectName='accountPanel')
1945+
1946+ def get_account_panel_count(self):
1947+ return self.get_account_panel_list().count
1948+
1949+ def get_account_panel_delegate(self, index):
1950+ return self.wait_select_single('AccountPanelItem', objectName='contact{}'.format(index))
1951+
1952+ def select_secret_chat(self):
1953+ action = self.wait_select_single('AccountPanelItem', objectName='secretChatItem')
1954+ self.pointing_device.click_object(action)
1955+
1956+ def select_group_chat(self):
1957+ action = self.wait_select_single('AccountPanelItem', objectName='groupChatItem')
1958+ self.pointing_device.click_object(action)
1959+
1960+ def select_contacts(self):
1961+ action = self.wait_select_single('AccountPanelItem', objectName='panelContacts')
1962+ self.pointing_device.click_object(action)
1963+
1964+ def select_settings(self):
1965+ action = self.wait_select_single('AccountPanelItem', objectName='panelSettings')
1966+ self.pointing_device.click_object(action)
1967+
1968+
1969+class AccountContactsPage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
1970+
1971+ def __init__(self, *args):
1972+ super(AccountContactsPage, self).__init__(*args)
1973+ self._index_of_first_online_contact = None
1974+
1975+
1976+ def _get_contacts_list(self):
1977+ return self.wait_select_single('MultipleSelectionListView', objectName='contactList')
1978+
1979+ def _get_contacts_count(self):
1980+ return self._get_contacts_list().count
1981+
1982+ def _get_contact_delegate(self, index):
1983+ return self.wait_select_single(
1984+ 'TelegramContactsListItem', objectName='contact{}'.format(index))
1985+
1986+ def _click_action_button(self, action_name):
1987+ action = self.wait_select_single(objectName='%s_button' % action_name)
1988+ if (action):
1989+ self.pointing_device.click_object(action)
1990+ else:
1991+ raise StateNotFoundError(action_name)
1992+
1993+
1994+ def select_first_online_contact(self):
1995+ #Select first contact if online (User MUST be online)
1996+ delegate = None
1997+ for index in range(self._get_contacts_count()):
1998+ delegate = self._get_contact_delegate(index)
1999+ if (delegate.isOnline):
2000+ self._index_of_first_online_contact = index
2001+ break
2002+
2003+ if delegate != None:
2004+ return delegate
2005+ else:
2006+ raise RuntimeError('Chat cannot be created. There are no online users')
2007+
2008+ def select_second_contact(self):
2009+ if self._index_of_first_online_contact is None:
2010+ raise RuntimeError('Please select first online contact before selecting a second contact')
2011+
2012+ #Select a second contact
2013+ delegate = None
2014+ for index in range(self._get_contacts_count()):
2015+ if index is not self._index_of_first_online_contact:
2016+ delegate = self._get_contact_delegate(index)
2017+ break
2018+
2019+ if delegate != None:
2020+ return delegate
2021+ else:
2022+ raise RuntimeError('Chat cannot be created. Cannot select second contact')
2023+
2024+ def select_contact_at_index(self, index):
2025+ delegate = self._get_contact_delegate(index)
2026+ return delegate
2027+
2028+ def enter_group_chat_title(self, title):
2029+ text_field = self.wait_select_single('TextField', objectName='groupChatTextField')
2030+ utilities.enter_text_in_text_area(text_field, title)
2031+ self._click_action_button("createGroupChatOK")
2032+
2033+
2034+class AccountDialogList(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2035+
2036+ @property
2037+ def dialog_count(self):
2038+ return self._get_dialog_list().count
2039+
2040+ def select_dialog_at_index(self, index):
2041+ selected_dialog = self._get_dialog_delegate(index)
2042+ self.pointing_device.click_object(selected_dialog)
2043+
2044+ def select_new_secret_chat(self):
2045+ count = self.dialog_count
2046+ count_including_new_secret_chat = count + 1
2047+ while (count != count_including_new_secret_chat):
2048+ count = self.dialog_count
2049+ self.select_first_dialog()
2050+
2051+ def _get_dialog_list(self):
2052+ return self.wait_select_single(objectName='dialogListView')
2053+
2054+ def _get_dialog_delegate(self, index):
2055+ return self.wait_select_single(
2056+ 'DialogsListItem', objectName='dialog{}'.format(index))
2057+
2058+
2059+class AccountDialogPage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2060+
2061+ def __init__(self, *args):
2062+ super(AccountDialogPage, self).__init__(*args)
2063+ self._account_message_list = None
2064+ self._message_area = None
2065+
2066+ @property
2067+ def account_message_list(self):
2068+ if self._account_message_list is None:
2069+ self._account_message_list = self.wait_select_single(AccountMessageList, objectName="accountMessageList")
2070+ return self._account_message_list
2071+
2072+ @property
2073+ def message_area(self):
2074+ if self._message_area is None:
2075+ self._message_area = self.wait_select_single(AccountSendMessage, objectName='accountSendMessageArea')
2076+ return self._message_area
2077+
2078+ def enter_message(self, message):
2079+ text_area = self.message_area.select_text_area()
2080+ utilities.enter_text_in_text_area(text_area, message)
2081+
2082+ def _get_sending_message_area(self):
2083+ return self.wait_select_single(AccountSendMessage, objectName='accountSendMessageArea')
2084+
2085+ def select_chat_info(self):
2086+ self.pointing_device.click_object(self.wait_select_single(objectName='groupInfo_button'))
2087+
2088+class AccountMessageList(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2089+
2090+ def __init__(self, *args):
2091+ super(AccountMessageList, self).__init__(*args)
2092+ self._messages = None
2093+
2094+ @property
2095+ def messages(self):
2096+ if self._messages is None:
2097+ self._messages = self.wait_select_single('MultipleSelectionListView', objectName="messagesListView")
2098+ return self._messages
2099+
2100+ def get_message_at_index(self, index):
2101+ return self.wait_select_single(
2102+ MessagesListItem, objectName='message{}'.format(index))
2103+
2104+
2105+class AccountSendMessage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2106+
2107+ def select_text_area(self):
2108+ return(self.wait_select_single('TextArea', objectName='sendMessageTextArea'))
2109+
2110+ def select_attach_or_send(self):
2111+ self.pointing_device.click_object(self.wait_select_single(objectName='sendMouseArea'))
2112+
2113+ def select_attach_sticker_option(self):
2114+ self.pointing_device.click_object(self.wait_select_single(objectName='stickerButton'))
2115+
2116+ def select_attach_photo_option(self):
2117+ self.pointing_device.click_object(self.wait_select_single(objectName="panelPhoto"))
2118+
2119+ def select_attach_video_option(self):
2120+ self.pointing_device.click_object(self.wait_select_single(objectName="panelVideo"))
2121+
2122+
2123+class MessagesListItem(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2124+
2125+ def __init__(self, *args):
2126+ super(MessagesListItem, self).__init__(*args)
2127+ self._message_status = None
2128+ self._message_status_image = None
2129+ self._message_label = None
2130+ self._account_message_media = None
2131+
2132+ @property
2133+ def message_status(self):
2134+ self._message_status = self.wait_select_single(objectName="messageStatus")
2135+ return self._message_status
2136+
2137+ @property
2138+ def message_status_image(self):
2139+ self._message_status_image = self.message_status.wait_select_single(objectName="statusImage")
2140+ return self._message_status_image
2141+
2142+ @property
2143+ def message_label(self):
2144+ self._message_label = self.wait_select_single(objectName="messageText")
2145+ return self._message_label
2146+
2147+ @property
2148+ def account_message_media(self):
2149+ self._account_message_media = self.wait_select_single(AccountMessageMedia, objectName="accountMessageMedia")
2150+ return self._account_message_media
2151+
2152+
2153+class AccountMessageMedia(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2154+
2155+ def __init__(self, *args):
2156+ super(AccountMessageMedia, self).__init__(*args)
2157+ self._media_message_status = None
2158+ self._media_message_status_image = None
2159+
2160+ @property
2161+ def media_message_status(self):
2162+ self._media_message_status = self.wait_select_single(objectName="mediaMessageStatus")
2163+ return self._media_message_status
2164+
2165+ @property
2166+ def media_message_status_image(self):
2167+ self._media_message_status_image = self.media_message_status.wait_select_single(objectName="statusImage")
2168+ return self._media_message_status_image
2169+
2170+
2171+class AccountSettings(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2172+
2173+ def __init__(self, *args):
2174+ super(AccountSettings, self).__init__(*args)
2175+ self._list_item_logout = None
2176+ self._settings_list = None
2177+ self._popup_logout = None
2178+
2179+ @property
2180+ def settings_list(self):
2181+ if self._settings_list is None:
2182+ self._settings_list = self.wait_select_single(objectName='settingsList')
2183+ return self._settings_list
2184+
2185+ @property
2186+ def list_item_logout(self):
2187+ if self._list_item_logout is None:
2188+ self._list_item_logout = self.wait_select_single(objectName="listItem_logout")
2189+ return self._list_item_logout
2190+
2191+ def select_list_item_logout(self):
2192+ self.settings_list.swipe_to_bottom()
2193+ self.pointing_device.click_object(self.list_item_logout)
2194+
2195+
2196+class ProfilePage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2197+
2198+ def __init__(self, *args):
2199+ super(ProfilePage, self).__init__(*args)
2200+
2201+ @property
2202+ def _member_list_count(self):
2203+ return self._get_member_list().count
2204+
2205+ def _get_member_list(self):
2206+ return self.wait_select_single(objectName='memberListView')
2207+
2208+ def _get_member_delegate(self, index):
2209+ return self.wait_select_single(
2210+ 'TelegramContactsListItem', objectName='dialog{}'.format(index))
2211+
2212+ def profile_member_at_index(self,index):
2213+ return self._get_member_delegate(index)
2214+
2215+ @property
2216+ def profile_user_name(self):
2217+ return self.wait_select_single(objectName="profileUserName")
2218+
2219+ @property
2220+ def profile_user_phone_number(self):
2221+ return self.wait_select_single(objectName="profilePhoneNumber")
2222+
2223+ @property
2224+ def profile_user_photo(self):
2225+ return self.wait_select_single(objectName="profileImageImport")
2226+
2227+ def select_user_photo(self):
2228+ return self.wait_select_single(objectName="profileImage")
2229+
2230+ @property
2231+ def switch_block(self):
2232+ return self.wait_select_single(objectName="switchBlock")
2233+
2234+ def select_switch_block(self):
2235+ self.pointing_device.click_object(self.wait_select_single(objectName="switchBlock"))
2236+
2237+ def select_switch_notification(self):
2238+ self.pointing_device.click_object(self.wait_select_single(objectName="switchNotification"))
2239+
2240+ def select_back_button(self):
2241+ # if platform.model() == "Desktop":
2242+ # action = self.wait_select_single(objectName='apl_back_action_button')
2243+ # else:
2244+ action = self.wait_select_single(objectName='profileBack_button')
2245+ self.pointing_device.click_object(action)
2246+
2247+class AuthCountriesPage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2248+
2249+ def __init__(self, *args):
2250+ super(AuthCountriesPage, self).__init__(*args)
2251+
2252+ def _click_action_button(self, action_name):
2253+ action = self.wait_select_single(objectName='%s_button' % action_name)
2254+ try:
2255+ self.pointing_device.click_object(action)
2256+ except:
2257+ raise StateNotFoundError(action_name)
2258+
2259+ def profile_member_at_index(self,index):
2260+ return self._get_member_delegate(index)
2261+
2262+ def enter_country_title_and_select(self, title):
2263+ # Select search icon
2264+ self._click_action_button("searchIcon")
2265+ # Type for country
2266+ text_field = self.wait_select_single('TextField', objectName='countryField')
2267+ utilities.enter_text_in_text_area(text_field, title)
2268+ # Select the search country
2269+ self.pointing_device.click_object(self.wait_select_single(objectName="united_kingdom"))
2270+
2271+class AuthNumberPage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2272+
2273+ def __init__(self, *args):
2274+ super(AuthNumberPage, self).__init__(*args)
2275+
2276+ def enter_phone_number(self, title):
2277+ # Enter text
2278+ text_field = self.wait_select_single('TextField', objectName='phoneNumberEntry')
2279+ utilities.enter_text_in_text_area(text_field, title)
2280+ # Press Send Code button
2281+ self.pointing_device.click_object(self.wait_select_single(objectName="doneButton"))
2282+
2283+class AuthCodePage(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
2284+
2285+ def __init__(self, *args):
2286+ super(AuthCodePage, self).__init__(*args)
2287+
2288+ def enter_code_in_textfield(self, title):
2289+ # Enter text
2290+ text_field = self.wait_select_single('TextField', objectName='verificationCodeEntry')
2291+ utilities.enter_text_in_text_area(text_field, title)
2292+
2293+ def press_sign_in_button(self):
2294+ # Press 'Sign In' button
2295+ self.pointing_device.click_object(self.wait_select_single(objectName="signInButton"))
2296\ No newline at end of file
2297
2298=== added file 'telegram/autopilot/telegram/setup.py'
2299--- telegram/autopilot/telegram/setup.py 1970-01-01 00:00:00 +0000
2300+++ telegram/autopilot/telegram/setup.py 2016-11-14 11:39:33 +0000
2301@@ -0,0 +1,57 @@
2302+#!/usr/bin/env python3
2303+
2304+#
2305+# Ubuntu System Tests
2306+# Copyright (C) 2014 Canonical
2307+#
2308+# This program is free software: you can redistribute it and/or modify
2309+# it under the terms of the GNU General Public License as published by
2310+# the Free Software Foundation, either version 3 of the License, or
2311+# (at your option) any later version.
2312+#
2313+# This program is distributed in the hope that it will be useful,
2314+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2315+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2316+# GNU General Public License for more details.
2317+#
2318+# You should have received a copy of the GNU General Public License
2319+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2320+#
2321+
2322+import sys
2323+from setuptools import find_packages, setup
2324+
2325+assert sys.version_info >= (3,), 'Python 3 is required'
2326+
2327+
2328+VERSION = '1.0'
2329+
2330+
2331+setup(
2332+ name='ubuntu-system-tests',
2333+ version=VERSION,
2334+ description='Automated tests for Ubuntu Touch images.',
2335+ author='Canonical Platform QA Team',
2336+ author_email='qa-team@lists.canonical.com',
2337+ url='https://launchpad.net/ubuntu-system-tests',
2338+ license='GPLv3',
2339+ packages=find_packages(),
2340+ package_data={
2341+ 'ubuntu_system_tests': ['tests/data/*/*']
2342+ },
2343+ install_requires=[
2344+ 'chardet',
2345+ 'python-debian',
2346+ 'requests',
2347+ 'retrying',
2348+ ],
2349+ entry_points={
2350+ 'console_scripts': [
2351+ 'ubuntu-system-tests = ubuntu_system_tests.run:main'
2352+ ]
2353+ },
2354+ test_suite='ubuntu_system_tests.selftests',
2355+ tests_require=[
2356+ 'python-subunit',
2357+ ]
2358+)
2359
2360=== added directory 'telegram/autopilot/telegram/tests'
2361=== added file 'telegram/autopilot/telegram/tests/__init__.py'
2362--- telegram/autopilot/telegram/tests/__init__.py 1970-01-01 00:00:00 +0000
2363+++ telegram/autopilot/telegram/tests/__init__.py 2016-11-14 11:39:33 +0000
2364@@ -0,0 +1,76 @@
2365+from autopilot.testcase import AutopilotTestCase
2366+from autopilot import platform
2367+from ubuntuuitoolkit import emulators as toolkit_emulators
2368+from autopilot.input import Mouse, Touch, Pointer
2369+from telegram import emulators
2370+from os.path import abspath, dirname, join
2371+from autopilot.matchers import Eventually
2372+from testtools.matchers import Equals
2373+
2374+import fixtures
2375+import ubuntuuitoolkit
2376+import subprocess
2377+
2378+class TelegramAppTestCase(AutopilotTestCase):
2379+
2380+ def __init__(self, *args):
2381+ super(TelegramAppTestCase, self).__init__(*args)
2382+ self._main_view = None
2383+
2384+ @property
2385+ def main_view(self):
2386+ if self._main_view is None:
2387+ self._main_view = self.app.wait_select_single(emulators.MainView)
2388+ return self._main_view
2389+
2390+ def setUp(self, parameter=""):
2391+ #self.pointing_device = Pointer(self.input_device_class.create())
2392+ super(TelegramAppTestCase, self).setUp()
2393+
2394+ subprocess.call(['pkill', 'telegram-app'])
2395+
2396+ #Preconditions: Logged In
2397+ if platform.model() == "Desktop":
2398+ self.app = self.launch_desktop_application(parameter)
2399+ else:
2400+ self.app = self.launch_mobile_application(parameter)
2401+ self.assertThat(self.main_view.visible, Eventually(Equals(True)))
2402+ # self.check_user_has_logged_in()
2403+
2404+ # if (self.check_user_has_logged_in()):
2405+ # self.assertThat(self.main_view.visible, Eventually(Equals(True)))
2406+ # else:
2407+ # raise RuntimeError("User must be logged in")
2408+
2409+
2410+ def launch_desktop_application(self, parameter):
2411+ #Setup the lib path environment variable using absolute path values, required by the app to access the necessary libs
2412+ library_path = abspath(join(dirname(__file__), '..', '..', '..', '..', 'build_desktop',))
2413+ envValue = library_path + ':$LD_LIBRARY_PATH'
2414+ self.useFixture(fixtures.EnvironmentVariable('LD_LIBRARY_PATH',envValue))
2415+
2416+ #Launch the test application using absolute path values
2417+ full_path = abspath(join(dirname(__file__), '..', '..', '..', '..', 'build_desktop','lib','x86_64-linux-gnu','bin','telegram'))
2418+ print(full_path + " " + parameter)
2419+ return self.launch_test_application(
2420+ full_path,
2421+ parameter,
2422+ app_type='qt',
2423+ emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
2424+
2425+ def launch_mobile_application(self, parameter):
2426+ return self.launch_click_package(
2427+ "com.ubuntu.telegram",
2428+ app_uris=['QT_LOAD_TESTABILITY=1'],
2429+ emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
2430+
2431+ def check_user_has_logged_in(self):
2432+ account_page = self.main_view.account_page
2433+ self.assertThat(account_page.visible, Eventually(Equals(True)))
2434+
2435+ # try:
2436+ # self.main_view.get_account_page()
2437+ # self.assertThat(self.main_view.account_page.visible, Eventually(Equals(True)))
2438+ # return True
2439+ # except:
2440+ # return False
2441\ No newline at end of file
2442
2443=== added file 'telegram/autopilot/telegram/tests/test_Logout.py'
2444--- telegram/autopilot/telegram/tests/test_Logout.py 1970-01-01 00:00:00 +0000
2445+++ telegram/autopilot/telegram/tests/test_Logout.py 2016-11-14 11:39:33 +0000
2446@@ -0,0 +1,52 @@
2447+from telegram.tests import TelegramAppTestCase
2448+from telegram import emulators
2449+
2450+import os
2451+import dbus
2452+import time
2453+import datetime
2454+import ubuntuuitoolkit
2455+
2456+from autopilot.matchers import Eventually
2457+from testtools.matchers import Equals
2458+from autopilot.utilities import sleep
2459+
2460+
2461+#from autopilot import logging as autopilot_logging
2462+#from telegram import displays_and_interactions as interactions
2463+
2464+
2465+class BaseTelegramTestCase(TelegramAppTestCase):
2466+
2467+ def setUp(self):
2468+ super(BaseTelegramTestCase, self).setUp()
2469+
2470+
2471+class Logout(BaseTelegramTestCase):
2472+
2473+ # Prerequisites:
2474+ # - User is already logged on
2475+ # - User has one contact which is online
2476+ # - Online contact is running on Telegram CLI
2477+
2478+
2479+ def test_UserLogout(self):
2480+
2481+ # Open the account panel by tapping the navigation menu icon
2482+ account_page = self.main_view.account_page
2483+ account_panel = account_page.open_account_panel()
2484+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
2485+
2486+ # Select the Settings option
2487+ account_panel.select_settings()
2488+
2489+ # Scroll to select the logout list item
2490+ apl = self.main_view.apl
2491+ settings_page = apl.settings_page
2492+ settings_page.select_list_item_logout()
2493+ sleep(3)
2494+ logout_confirm_dialog = self.app.wait_select_single(objectName='logoutDialog')
2495+ self.main_view.pointing_device.click_object(logout_confirm_dialog.wait_select_single(objectName='logoutConfirm'))
2496+
2497+ # Checks that the Intro Page is now active
2498+ introPage = apl.intro_page
2499
2500=== added file 'telegram/autopilot/telegram/tests/test_MessageDisplay.py'
2501--- telegram/autopilot/telegram/tests/test_MessageDisplay.py 1970-01-01 00:00:00 +0000
2502+++ telegram/autopilot/telegram/tests/test_MessageDisplay.py 2016-11-14 11:39:33 +0000
2503@@ -0,0 +1,205 @@
2504+from telegram.tests import TelegramAppTestCase
2505+from telegram import emulators
2506+from telegram import utilities
2507+
2508+import os
2509+import dbus
2510+import time
2511+import datetime
2512+# import subprocess
2513+import ubuntuuitoolkit
2514+
2515+from autopilot.matchers import Eventually
2516+from testtools.matchers import Equals
2517+from autopilot.display import Display
2518+from autopilot import platform
2519+from autopilot.utilities import sleep
2520+
2521+#from autopilot import logging as autopilot_logging
2522+#from telegram import displays_and_interactions as interactions
2523+
2524+messageTypeText = "Autopilot: Text DO NOT REPLY"
2525+messageTypeSpecialChar = "Autopilot: !$%^&*""()-_''=+?; DO NOT REPLY"
2526+messageTypeUrl = "http://google.co.uk DO NOT REPLY"
2527+
2528+message_status_received = "qrc:/qml/files/check_single_green.png"
2529+message_status_read = "qrc:/qml/files/check_double_green.png"
2530+
2531+class BaseTelegramTestCase(TelegramAppTestCase):
2532+
2533+ def setUp(self):
2534+ super(BaseTelegramTestCase, self).setUp()
2535+
2536+class SecretChatTests(BaseTelegramTestCase):
2537+
2538+ scenarios = [
2539+ ('dialog_msgText', {'input': "dialog_msgText"}),
2540+ ('dialog_msgSpecialChar', {'input': "dialog_msgSpecialChar"}),
2541+ ('dialog_msgUrl', {'input': "dialog_msgUrl"}),
2542+ ]
2543+
2544+ def test_create_secret_chat(self):
2545+ # Open the account panel by tapping the navigation menu icon
2546+ account_page = self.main_view.account_page
2547+ account_panel = account_page.open_account_panel()
2548+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
2549+
2550+ # Select the secret chat option
2551+ account_panel.select_secret_chat()
2552+
2553+ contact_page = self.main_view.apl.contacts_page
2554+
2555+ # PAZ always select online user - Done
2556+ # Select first contact
2557+ self.main_view.pointing_device.click_object(contact_page.select_first_online_contact())
2558+
2559+ dialog_list_page = account_page.get_dialog_list_page()
2560+ # Give chance for app to add the secret chat to top of chat list
2561+ sleep(3)
2562+ # Select the top chat
2563+ dialog_list_page.select_dialog_at_index(0)
2564+
2565+ dialog_page = self.main_view.apl.dialog_page
2566+ message_list = dialog_page.account_message_list
2567+ inital_count = message_list.messages.count
2568+
2569+ if self.input == "dialog_msgSpecialChar":
2570+ dialog_page.enter_message(messageTypeSpecialChar)
2571+ dialog_page.message_area.select_attach_or_send()
2572+
2573+ elif self.input == "dialog_msgUrl":
2574+ dialog_page.enter_message(messageTypeUrl)
2575+ dialog_page.message_area.select_attach_or_send()
2576+
2577+ elif self.input == "dialog_msgText":
2578+ dialog_page.enter_message(messageTypeText)
2579+ dialog_page.message_area.select_attach_or_send()
2580+
2581+ # Wait for the message to be sent and allow for network latency
2582+ # Check that the single tick image is displayed for the sent message
2583+ sleep(2)
2584+
2585+ message = message_list.get_message_at_index(0)
2586+ self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_received)))
2587+
2588+ # Check that the double tick image is displayed for the read message
2589+ self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_read)))
2590+
2591+ # PAZ I believe you need to tap on the URL to make sure it opens up in a browser. Not just
2592+ # check that the URL received is the same as the URL sent
2593+
2594+ # ASH - I don't believe theres a way to determine that Browser app opens up from taping
2595+ # a link. Could be wrong but some help on this would be appreciated.
2596+
2597+ # ASH - Hold off. Needs to be rethinked
2598+
2599+ # if self.input == "dialog_msgUrl":
2600+ # #Click on link
2601+ # self.main_view.pointing_device.click_object(message.message_label)
2602+ # #Check hovered link is same as entered link
2603+ # self.assertThat(message.message_label.hoveredLink, Eventually(Equals(messageTypeUrl)))
2604+
2605+ #PAZ - always need to check for double tick
2606+
2607+class GroupChatTests(BaseTelegramTestCase):
2608+
2609+ scenarios = [
2610+ ('dialog_msgText', {'input': "dialog_msgText"}),
2611+ ('dialog_msgSpecialChar', {'input': "dialog_msgSpecialChar"}),
2612+ ('dialog_msgUrl', {'input': "dialog_msgUrl"}),
2613+ ]
2614+
2615+ def test_create_group_chat(self):
2616+ # Open the account panel by tapping the navigation menu icon
2617+ account_page = self.main_view.account_page
2618+ account_panel = account_page.open_account_panel()
2619+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
2620+
2621+ # Select the secret chat option
2622+ account_panel.select_group_chat()
2623+ contact_page = self.main_view.apl.contacts_page
2624+
2625+ # Select first contact
2626+ self.main_view.pointing_device.click_object(contact_page.select_first_online_contact())
2627+ # Select second contact
2628+ self.main_view.pointing_device.click_object(contact_page.select_second_contact())
2629+
2630+ contact_page.enter_group_chat_title('NewGroupTitle')
2631+
2632+ dialog_list_page = account_page.get_dialog_list_page()
2633+ # Give chance for app to add the group chat to top of chat list
2634+ sleep(3)
2635+ # Select the top chat
2636+ dialog_list_page.select_dialog_at_index(0)
2637+
2638+ dialog_page = self.main_view.apl.dialog_page
2639+ message_list = dialog_page.account_message_list
2640+ inital_count = message_list.messages.count
2641+
2642+ if self.input == "dialog_msgSpecialChar":
2643+ dialog_page.enter_message(messageTypeSpecialChar)
2644+ dialog_page.message_area.select_attach_or_send()
2645+
2646+ elif self.input == "dialog_msgUrl":
2647+ dialog_page.enter_message(messageTypeUrl)
2648+ dialog_page.message_area.select_attach_or_send()
2649+
2650+ elif self.input == "dialog_msgText":
2651+ dialog_page.enter_message(messageTypeText)
2652+ dialog_page.message_area.select_attach_or_send()
2653+
2654+ # Wait for the message to be sent and allow for network latency
2655+ # Check that the single tick image is displayed for the sent message
2656+ sleep(1)
2657+
2658+ message = message_list.get_message_at_index(0)
2659+ self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_received)))
2660+
2661+ # Check that the double tick image is displayed for the read message
2662+ self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_read)))
2663+
2664+class BasicMessagingTests(BaseTelegramTestCase):
2665+
2666+ scenarios = [
2667+ ('dialog_msgText', {'input': "dialog_msgText"}),
2668+ ('dialog_msgSpecialChar', {'input': "dialog_msgSpecialChar"}),
2669+ ('dialog_msgUrl', {'input': "dialog_msgUrl"}),
2670+ ]
2671+
2672+ def test_create_basic_chat(self):
2673+ # Open the account panel by tapping the navigation menu icon
2674+ account_page = self.main_view.account_page
2675+ account_panel = account_page.open_account_panel()
2676+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
2677+
2678+ # Select Contacts option
2679+ account_panel.select_contacts()
2680+
2681+ #Select first contact
2682+ contact_page = self.main_view.apl.contacts_page
2683+ self.main_view.pointing_device.click_object(contact_page.select_first_online_contact())
2684+
2685+ dialog_page = self.main_view.apl.dialog_page
2686+ message_list = dialog_page.account_message_list
2687+ inital_count = message_list.messages.count
2688+
2689+ if self.input == "dialog_msgSpecialChar":
2690+ dialog_page.enter_message(messageTypeSpecialChar)
2691+ dialog_page.message_area.select_attach_or_send()
2692+
2693+ elif self.input == "dialog_msgUrl":
2694+ dialog_page.enter_message(messageTypeUrl)
2695+ dialog_page.message_area.select_attach_or_send()
2696+
2697+ elif self.input == "dialog_msgText":
2698+ dialog_page.enter_message(messageTypeText)
2699+ dialog_page.message_area.select_attach_or_send()
2700+
2701+ # Check that the single tick image is displayed for the sent message
2702+ sleep(1)
2703+
2704+ message = message_list.get_message_at_index(0)
2705+ self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_received)))
2706+
2707+ # Check that the double tick image is displayed for the read message
2708+ self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_read)))
2709\ No newline at end of file
2710
2711=== added file 'telegram/autopilot/telegram/tests/test_Messaging.py'
2712--- telegram/autopilot/telegram/tests/test_Messaging.py 1970-01-01 00:00:00 +0000
2713+++ telegram/autopilot/telegram/tests/test_Messaging.py 2016-11-14 11:39:33 +0000
2714@@ -0,0 +1,402 @@
2715+from telegram.tests import TelegramAppTestCase
2716+from telegram import emulators
2717+
2718+import os
2719+import dbus
2720+import time
2721+import datetime
2722+import threading
2723+# import subprocess
2724+import ubuntuuitoolkit
2725+
2726+from autopilot.matchers import Eventually
2727+from testtools.matchers import Equals, NotEquals
2728+from autopilot.display import Display
2729+from autopilot import platform
2730+from autopilot.utilities import sleep
2731+
2732+
2733+#from autopilot import logging as autopilot_logging
2734+#from telegram import displays_and_interactions as interactions
2735+
2736+message_sending_image = "qrc:/qml/files/msg_clock.png"
2737+message_received_image = "qrc:/qml/files/check_single_green.png"
2738+message_read_image = "qrc:/qml/files/check_double_green.png"
2739+media_received_image = "qrc:/qml/files/check_single_white.png"
2740+media_read_image = "qrc:/qml/files/check_double_white.png"
2741+
2742+
2743+class BaseTelegramTestCase(TelegramAppTestCase):
2744+
2745+ def setUp(self):
2746+ super(BaseTelegramTestCase, self).setUp()
2747+
2748+
2749+class SecretMessaging(BaseTelegramTestCase):
2750+
2751+ # Prerequisites:
2752+ # - User is already logged on
2753+ # - User has one contact which is online
2754+ # - Online contact is running on Telegram CLI
2755+
2756+ scenarios = [
2757+ ('textMessageSend', {'input': "textMessageSend"}),
2758+ ('textMessageSendReceive', {'input': "textMessageSendReceive"}),
2759+ ('photoMessageSend', {'input': "photoMessageSend"}),
2760+ # ('photoMessageReceive', {'input': "photoMessageReceive"}),
2761+ ]
2762+
2763+ def test_SecretMessage(self):
2764+
2765+ # Note the number of dialogs in the dialog list at the start of the test
2766+ account_page = self.main_view.account_page
2767+ dialog_list_page = account_page.get_dialog_list_page()
2768+ count = dialog_list_page.dialog_count
2769+
2770+ # Open the account panel by tapping the navigation menu icon
2771+ account_panel = account_page.open_account_panel()
2772+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
2773+
2774+ # Select the secret chat option
2775+ account_panel.select_secret_chat()
2776+
2777+ # Select an online contact
2778+ apl = self.main_view.apl
2779+ contacts_page = apl.contacts_page
2780+ recipient = contacts_page.select_first_online_contact()
2781+ self.main_view.pointing_device.click_object(recipient)
2782+
2783+ # Create a new secret chat
2784+ self.assertThat(count, Eventually(Equals(count + 1)))
2785+ dialog_list_page.select_dialog_at_index(0)
2786+ dialog_page = apl.dialog_page
2787+
2788+ # Check that only system message is being displayed
2789+ message_list = dialog_page.account_message_list
2790+ initial_count = message_list.messages.count
2791+ self.assertThat(initial_count, Equals(1))
2792+
2793+ status_received = message_received_image
2794+ status_read = message_read_image
2795+
2796+ if "textMessage" in self.input or self.input == "photoMessageReceive":
2797+ # Send the first message
2798+
2799+ ts = time.time()
2800+ timestamp = datetime.datetime.fromtimestamp(ts).strftime('%y:%m:%d,%H:%M:%S')
2801+ message_to_send = "Autopilot:" + timestamp
2802+ if self.input == "textMessageSend":
2803+ message_to_send = message_to_send + " DO NOT REPLY"
2804+ elif self.input == "photoMessageReceive":
2805+ message_to_send = message_to_send + " SEND IMAGE"
2806+
2807+ dialog_page.enter_message(message_to_send)
2808+ dialog_page.message_area.select_attach_or_send()
2809+
2810+ elif self.input == "photoMessageSend":
2811+
2812+ if platform.model() == "Desktop":
2813+ return
2814+
2815+ dialog_page.message_area.select_attach_or_send()
2816+ dialog_page.message_area.select_attach_photo_option()
2817+ self.main_view.select_content_hub_app("Camera")
2818+
2819+ # Allow time to open the app
2820+ sleep(5)
2821+
2822+ display = Display.create()
2823+ screen_width = display.get_screen_width()
2824+ screen_height = display.get_screen_height()
2825+ button_x_pos = screen_width / 2.0
2826+ button_y_pos = screen_height - 100.0
2827+
2828+ # Click on the take photo button
2829+ self.main_view.pointing_device.move(button_x_pos, button_y_pos)
2830+ self.main_view.pointing_device.click()
2831+
2832+ # Allow time to take the photo
2833+ sleep(5)
2834+
2835+ # Tap the tick to return to Telegram
2836+ self.main_view.pointing_device.move(button_x_pos, button_y_pos)
2837+ self.main_view.pointing_device.click()
2838+
2839+ status_received = media_received_image
2840+ status_read = media_read_image
2841+
2842+ # Allow time for photo to be sent
2843+ sleep(5)
2844+
2845+ # Check that sent message appears in the dialog content
2846+ self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 1)))
2847+
2848+ # Check that the message received image is displayed for the sent message
2849+ index_of_sent_message = 0
2850+ message = message_list.get_message_at_index(index_of_sent_message)
2851+ status_image = message.message_status_image
2852+
2853+ if self.input == "photoMessageSend" and platform.model() != "Desktop":
2854+ status_image = message.account_message_media.media_message_status_image
2855+
2856+ self.assertThat(status_image.source, Eventually(Equals(status_received)))
2857+
2858+ if "Receive" in self.input:
2859+
2860+ index_of_sent_message = index_of_sent_message + 1
2861+
2862+ # Check for reply
2863+ self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 2)))
2864+
2865+ # Check that the message read image is displayed for the sent message
2866+ message = message_list.get_message_at_index(index_of_sent_message)
2867+ status_image = message.message_status_image
2868+
2869+ if self.input == "photoMessageSend" and platform.model() != "Desktop":
2870+ status_image = message.account_message_media.media_message_status_image
2871+
2872+ self.assertThat(status_image.source, Eventually(Equals(status_read)))
2873+
2874+
2875+
2876+class BasicMessaging(BaseTelegramTestCase):
2877+
2878+ scenarios = [
2879+ ('textMessageSend', {'input': "textMessageSend"}),
2880+ ('textMessageSendReceive', {'input': "textMessageSendReceive"}),
2881+ ('photoMessageSend', {'input': "photoMessageSend"}),
2882+ ('photoMessageReceive', {'input': "photoMessageReceive"}),
2883+ ]
2884+
2885+ def test_BasicMessage(self):
2886+
2887+ # Open the account panel by tapping the navigation menu icon
2888+ account_page = self.main_view.account_page
2889+ account_panel = account_page.open_account_panel()
2890+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
2891+
2892+ # Select contacts
2893+ account_panel.select_contacts()
2894+
2895+ # Select an online contact
2896+ apl = self.main_view.apl
2897+ contacts_page = apl.contacts_page
2898+ recipient = contacts_page.select_first_online_contact()
2899+ self.main_view.pointing_device.click_object(recipient)
2900+
2901+ # Check that no messages are being displayed
2902+ dialog_page = apl.dialog_page
2903+ message_list = dialog_page.account_message_list
2904+ initial_count = message_list.messages.count
2905+
2906+ # Initialise status image values
2907+ status_received = message_received_image
2908+ status_read = message_read_image
2909+
2910+ if "textMessage" in self.input or self.input == "photoMessageReceive":
2911+
2912+ # Send the first message
2913+ ts = time.time()
2914+ timestamp = datetime.datetime.fromtimestamp(ts).strftime('%y:%m:%d,%H:%M:%S')
2915+ message_to_send = "Autopilot" + timestamp
2916+ if self.input == "textMessageSend":
2917+ message_to_send = message_to_send + " DO NOT REPLY"
2918+ elif self.input == "photoMessageReceive":
2919+ message_to_send = message_to_send + " SEND IMAGE"
2920+
2921+ dialog_page.enter_message(message_to_send)
2922+ dialog_page.message_area.select_attach_or_send()
2923+
2924+ elif self.input == "photoMessageSend":
2925+
2926+ if platform.model() == "Desktop":
2927+ return
2928+
2929+ dialog_page.message_area.select_attach_or_send()
2930+ dialog_page.message_area.select_attach_photo_option()
2931+ self.main_view.select_content_hub_app("Camera")
2932+
2933+ # Allow time to open the app
2934+ sleep(5)
2935+
2936+ display = Display.create()
2937+ screen_width = display.get_screen_width()
2938+ screen_height = display.get_screen_height()
2939+ button_x_pos = screen_width / 2.0
2940+ button_y_pos = screen_height - 100.0
2941+
2942+ # Click on the take photo button
2943+ self.main_view.pointing_device.move(button_x_pos, button_y_pos)
2944+ self.main_view.pointing_device.click()
2945+
2946+ # Allow time to take the photo
2947+ sleep(5)
2948+
2949+ # Tap the tick to return to Telegram
2950+ self.main_view.pointing_device.move(button_x_pos, button_y_pos)
2951+ self.main_view.pointing_device.click()
2952+
2953+ status_received = media_received_image
2954+ status_read = media_read_image
2955+
2956+ # Allow time for photo to be sent
2957+ sleep(5)
2958+
2959+ # Check that sent message appears in the dialog content
2960+ self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 1)))
2961+
2962+ # Check that the message received image is displayed for the sent message
2963+ index_of_sent_message = 0
2964+ message = message_list.get_message_at_index(index_of_sent_message)
2965+ status_image = message.message_status_image
2966+
2967+ if self.input == "photoMessageSend" and platform.model() != "Desktop":
2968+ status_image = message.account_message_media.media_message_status_image
2969+
2970+ self.assertThat(status_image.source, Eventually(Equals(status_received)))
2971+
2972+ if "Receive" in self.input:
2973+
2974+ index_of_sent_message = index_of_sent_message + 1
2975+
2976+ # Check for reply
2977+ self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 2)))
2978+
2979+ # Check that the message read image is displayed for the sent message
2980+ message = message_list.get_message_at_index(index_of_sent_message)
2981+ status_image = message.message_status_image
2982+
2983+ if self.input == "photoMessageSend" and platform.model() != "Desktop":
2984+ status_image = message.account_message_media.media_message_status_image
2985+
2986+ self.assertThat(status_image.source, Eventually(Equals(status_read)))
2987+
2988+
2989+class GroupMessaging(BaseTelegramTestCase):
2990+
2991+ scenarios = [
2992+ ('textMessageSend', {'input': "textMessageSend"}),
2993+ ('textMessageSendReceive', {'input': "textMessageSendReceive"}),
2994+ ('photoMessageSend', {'input': "photoMessageSend"}),
2995+ ('photoMessageReceive', {'input': "photoMessageReceive"}),
2996+ ]
2997+
2998+ def test_GroupMessage(self):
2999+
3000+ # Note the number of dialogs in the dialog list at the start of the test
3001+ account_page = self.main_view.account_page
3002+ dialog_list_page = account_page.get_dialog_list_page()
3003+ count = dialog_list_page.dialog_count
3004+
3005+ # Open the account panel by tapping the navigation menu icon
3006+ account_panel = account_page.open_account_panel()
3007+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
3008+
3009+ # Select the group chat option
3010+ account_panel.select_group_chat()
3011+
3012+ # Select an online contact
3013+ apl = self.main_view.apl
3014+ contacts_page = apl.contacts_page
3015+ online_member_one = contacts_page.select_first_online_contact()
3016+ self.main_view.pointing_device.click_object(online_member_one)
3017+
3018+ # Select another contact
3019+ member_two = contacts_page.select_second_contact()
3020+ self.main_view.pointing_device.click_object(member_two)
3021+
3022+ # Add a group chat title
3023+ contacts_page.enter_group_chat_title('Autopilot Group Messaging')
3024+
3025+ # Select the group chat dialog just created
3026+ self.assertThat(count, Eventually(Equals(count + 1)))
3027+ dialog_list_page.select_dialog_at_index(0)
3028+ dialog_page = apl.dialog_page
3029+
3030+ # Check that only system message is being displayed
3031+ message_list = dialog_page.account_message_list
3032+ initial_count = message_list.messages.count
3033+ self.assertThat(initial_count, Equals(1))
3034+
3035+ # Initialise status image values
3036+ status_received = message_received_image
3037+ status_read = message_read_image
3038+
3039+ if "textMessage" in self.input or self.input == "photoMessageReceive":
3040+
3041+ # Generate and send the first message
3042+ ts = time.time()
3043+ timestamp = datetime.datetime.fromtimestamp(ts).strftime('%y:%m:%d,%H:%M:%S')
3044+ message_to_send = "Autopilot:" + timestamp
3045+ if self.input == "textMessageSend":
3046+ message_to_send = message_to_send + " DO NOT REPLY"
3047+ elif self.input == "photoMessageReceive":
3048+ message_to_send = message_to_send + " SEND IMAGE"
3049+
3050+ dialog_page.enter_message(message_to_send)
3051+ dialog_page.message_area.select_attach_or_send()
3052+
3053+ elif self.input == "photoMessageSend":
3054+
3055+ if platform.model() == "Desktop":
3056+ return
3057+
3058+ dialog_page.message_area.select_attach_or_send()
3059+ sleep(1)
3060+ dialog_page.message_area.select_attach_photo_option()
3061+ self.main_view.select_content_hub_app("Camera")
3062+
3063+ # Allow time to open the app
3064+ sleep(5)
3065+
3066+ display = Display.create()
3067+ screen_width = display.get_screen_width()
3068+ screen_height = display.get_screen_height()
3069+ button_x_pos = screen_width / 2.0
3070+ button_y_pos = screen_height - 100.0
3071+
3072+ # Click on the take photo button
3073+ self.main_view.pointing_device.move(button_x_pos, button_y_pos)
3074+ self.main_view.pointing_device.click()
3075+
3076+ # Allow time to take the photo
3077+ sleep(5)
3078+
3079+ # Tap the tick to return to Telegram
3080+ self.main_view.pointing_device.move(button_x_pos, button_y_pos)
3081+ self.main_view.pointing_device.click()
3082+
3083+ status_received = media_received_image
3084+ status_read = media_read_image
3085+
3086+ # Allow time for photo to be sent
3087+ sleep(5)
3088+
3089+ # Check that sent message appears in the dialog content
3090+ self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 1)))
3091+
3092+ # Check that the message received image is displayed for the sent message
3093+ index_of_sent_message = 0
3094+ message = message_list.get_message_at_index(index_of_sent_message)
3095+ status_image = message.message_status_image
3096+
3097+ if self.input == "photoMessageSend" and platform.model() != "Desktop":
3098+ status_image = message.account_message_media.media_message_status_image
3099+
3100+ self.assertThat(status_image.source, Eventually(Equals(status_received)))
3101+
3102+ if "Receive" in self.input:
3103+
3104+ index_of_sent_message = index_of_sent_message + 1
3105+
3106+ # Check for reply
3107+ self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 2)))
3108+
3109+ # Check that the double tick image is displayed for the read message
3110+ message = message_list.get_message_at_index(index_of_sent_message)
3111+ status_image = message.message_status_image
3112+
3113+ if self.input == "photoMessageSend" and platform.model() != "Desktop":
3114+ status_image = message.account_message_media.media_message_status_image
3115+
3116+ self.assertThat(status_image.source, Eventually(Equals(status_read)))
3117
3118=== added file 'telegram/autopilot/telegram/tests/test_Offline.py'
3119--- telegram/autopilot/telegram/tests/test_Offline.py 1970-01-01 00:00:00 +0000
3120+++ telegram/autopilot/telegram/tests/test_Offline.py 2016-11-14 11:39:33 +0000
3121@@ -0,0 +1,54 @@
3122+from telegram.tests import TelegramAppTestCase
3123+from telegram import emulators
3124+
3125+# import subprocess
3126+import ubuntuuitoolkit
3127+
3128+from autopilot.matchers import Eventually
3129+from testtools.matchers import Equals
3130+from autopilot.display import Display
3131+from autopilot import platform
3132+from testtools import skipUnless
3133+
3134+class BaseTelegramTestCase(TelegramAppTestCase):
3135+
3136+ def setUp(self):
3137+ super(BaseTelegramTestCase, self).setUp()
3138+
3139+class OfflineTests(BaseTelegramTestCase):
3140+
3141+ @skipUnless(
3142+ platform.model() != "Desktop",
3143+ "Offline Test is only available on Device"
3144+ )
3145+
3146+ def test_check_for_offline_message(self):
3147+ display = Display.create()
3148+ screenWidth = display.get_screen_width()
3149+ screenHeight = display.get_screen_height()
3150+
3151+ #Pull menu from top
3152+ self.main_view.pointing_device.drag(screenWidth-202, 0, screenWidth-202, screenHeight)
3153+ #Tap Flight Mode switch
3154+ self.main_view.pointing_device.move(screenWidth-130,150)
3155+ self.main_view.pointing_device.click()
3156+ #Close menu
3157+ self.main_view.pointing_device.drag(0,screenHeight, 0,0)
3158+
3159+ account_page = self.main_view.account_page
3160+
3161+ # if account_page.get_default_header().title in ('Telegram', 'Connecting...'):
3162+ # print("WARNING - Please turn ON Airplane Mode")
3163+
3164+ self.assertThat(account_page.get_default_header().title, Eventually(Equals("Waiting for network...")))
3165+
3166+ #Pull menu from top
3167+ self.main_view.pointing_device.drag(screenWidth-180, 0, screenWidth-180, screenHeight)
3168+ #Tap Flight Mode switch
3169+ self.main_view.pointing_device.move(screenWidth-130,150)
3170+ self.main_view.pointing_device.click()
3171+ #Close menu
3172+ self.main_view.pointing_device.drag(0,screenHeight, 0,0)
3173+
3174+ # Check header no longer says offline message
3175+ self.assertThat(account_page.get_default_header().title, Eventually(Equals("Telegram")))
3176
3177=== added file 'telegram/autopilot/telegram/tests/test_Profile.py'
3178--- telegram/autopilot/telegram/tests/test_Profile.py 1970-01-01 00:00:00 +0000
3179+++ telegram/autopilot/telegram/tests/test_Profile.py 2016-11-14 11:39:33 +0000
3180@@ -0,0 +1,186 @@
3181+from telegram.tests import TelegramAppTestCase
3182+from telegram import emulators
3183+from telegram import utilities
3184+
3185+import os
3186+import dbus
3187+import time
3188+import datetime
3189+# import subprocess
3190+import ubuntuuitoolkit
3191+
3192+from autopilot.matchers import Eventually
3193+from testtools.matchers import Equals
3194+from autopilot.utilities import sleep
3195+
3196+messageTypeText = "Autopilot: Text INSTANT REPLY"
3197+
3198+class BaseTelegramTestCase(TelegramAppTestCase):
3199+
3200+ def setUp(self):
3201+ super(BaseTelegramTestCase, self).setUp()
3202+
3203+class ProfileTests(BaseTelegramTestCase):
3204+
3205+ def test_check_group_to_verify_members(self):
3206+ # Open the account panel by tapping the navigation menu icon
3207+ account_page = self.main_view.account_page
3208+ account_panel = account_page.open_account_panel()
3209+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
3210+
3211+ # Select the secret chat option
3212+ account_panel.select_group_chat()
3213+
3214+ # Select first online contact
3215+ contacts_page = self.main_view.apl.contacts_page
3216+
3217+ # Select first contact
3218+ self.main_view.pointing_device.click_object(contacts_page.select_contact_at_index(0))
3219+ # Temporarily save fullname of contact
3220+ tempUser1Name = contacts_page.select_contact_at_index(0).fullName
3221+
3222+ # Select second contact
3223+ self.main_view.pointing_device.click_object(contacts_page.select_contact_at_index(1))
3224+ tempUser2Name = contacts_page.select_contact_at_index(1).fullName
3225+
3226+ #Enter group title and press Enter
3227+ contacts_page.enter_group_chat_title('ProfileTest-NewGroup')
3228+
3229+ #Assign dialog list
3230+ account_page = self.main_view.account_page
3231+ dialog_list_page = account_page.get_dialog_list_page()
3232+ count = dialog_list_page.dialog_count
3233+ self.assertThat(count, Eventually(Equals(count + 1)))
3234+ dialog_list_page.select_dialog_at_index(0)
3235+
3236+ #Press groupInfo button
3237+ self.main_view.apl.dialog_page.select_chat_info()
3238+
3239+ #Assign ProfilePage
3240+ profile_page = self.main_view.apl.profile_page
3241+
3242+ # Check user 1 is listed
3243+ self.assertThat(str(profile_page.profile_member_at_index(1).title), Equals(tempUser1Name))
3244+ # Check user 2 is listed
3245+ self.assertThat(str(profile_page.profile_member_at_index(0).title), Equals(tempUser2Name))
3246+
3247+
3248+ def test_check_blocked_user(self):
3249+ # Open the account panel by tapping the navigation menu icon
3250+ account_page = self.main_view.account_page
3251+ account_panel = account_page.open_account_panel()
3252+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
3253+
3254+ # Select Contacts option
3255+ account_panel.select_contacts()
3256+
3257+ #Select first contact
3258+ contacts_page = self.main_view.apl.contacts_page
3259+ recipient = contacts_page.select_first_online_contact()
3260+ self.main_view.pointing_device.click_object(recipient)
3261+
3262+ dialog_page = self.main_view.apl.dialog_page
3263+ message_list = dialog_page.account_message_list
3264+ inital_count = message_list.messages.count
3265+
3266+ #Send message
3267+ dialog_page.enter_message(messageTypeText)
3268+ dialog_page.message_area.select_attach_or_send()
3269+
3270+ #Check received reply
3271+ self.assertThat(message_list.messages.count, Eventually(Equals(inital_count + 2)))
3272+
3273+ #Tap the groupInfo button
3274+ self.main_view.apl.dialog_page.select_chat_info()
3275+ #Assign ProfilePage
3276+ profile_page = self.main_view.apl.profile_page
3277+ #Turn on Block contact
3278+ switch = profile_page.switch_block
3279+ self.main_view.pointing_device.click_object(switch)
3280+ #Verify blocked user switch is turned ON
3281+ self.assertThat(switch.checked, Equals(True))
3282+ #Go back to dialog page
3283+ profile_page.select_back_button()
3284+ self.main_view.apl.clear_profile_page()
3285+
3286+ #Send message
3287+ dialog_page.enter_message(messageTypeText)
3288+ dialog_page.message_area.select_attach_or_send()
3289+
3290+ # Check that the sent message was read
3291+ message = None
3292+ for idx in range(0, message_list.messages.count):
3293+ message = message_list.get_message_at_index(idx)
3294+ if message.message_label.text == messageTypeText:
3295+ self.assertThat(message.message_status_image.source, Eventually(Equals("qrc:/qml/files/check_double_green.png")))
3296+ break
3297+ else:
3298+ message = None
3299+ self.assertThat(message is None, Equals(False))
3300+
3301+ # Check that no response was received (wait for 10 seconds)
3302+ sleep(10)
3303+ self.assertThat(message_list.messages.count, Equals(inital_count + 3))
3304+
3305+ #Tap the groupInfo button
3306+ self.main_view.apl.dialog_page.select_chat_info()
3307+ #Assign ProfilePage
3308+ profile_page = self.main_view.apl.profile_page
3309+ #Turn off Block contact.
3310+ switch = profile_page.switch_block
3311+ self.assertThat(switch.checked, Eventually(Equals(True)))
3312+ self.main_view.pointing_device.click_object(switch)
3313+ #Verify blocked user switch is turned OFF
3314+ self.assertThat(switch.checked, Eventually(Equals(False)))
3315+ #Go back to dialog page
3316+ profile_page.select_back_button()
3317+
3318+ #Check number of messages and send message
3319+ self.assertThat(message_list.messages.count, Equals(inital_count + 3))
3320+ #Send message
3321+ dialog_page.enter_message(messageTypeText)
3322+ dialog_page.message_area.select_attach_or_send()
3323+
3324+ #Check received reply
3325+ self.assertThat(message_list.messages.count, Eventually(Equals(inital_count + 5)))
3326+
3327+class ProfileDetails(BaseTelegramTestCase):
3328+
3329+ def test_verify_profile_details(self):
3330+ # Open the account panel by tapping the navigation menu icon
3331+ account_page = self.main_view.account_page
3332+ account_panel = account_page.open_account_panel()
3333+ self.assertThat(account_panel.opened, Eventually(Equals(True)))
3334+
3335+ # Select Contacts option
3336+ account_panel.select_contacts()
3337+
3338+ #Select first contact
3339+ contact_page = self.main_view.apl.contacts_page
3340+ contact = contact_page.select_contact_at_index(0)
3341+
3342+ self.main_view.pointing_device.click_object(contact)
3343+
3344+ self.main_view.apl.dialog_page.select_chat_info()
3345+
3346+ profile_page = self.main_view.apl.profile_page
3347+
3348+ # print(profile_page.profile_user_photo.get_properties())
3349+
3350+ # print("IMAGE SRC: " + profile_page.profile_user_photo.source)
3351+
3352+ sleep(3)
3353+
3354+ if profile_page.select_user_photo() is None:
3355+ #User does not have a profile image
3356+ print('WARNING - Profiles - Contact does not have Profile image')
3357+ else:
3358+ self.assertThat(profile_page.select_user_photo() is not None, Equals(True))
3359+
3360+ # Check the user has a name
3361+ if profile_page.profile_user_name.text is None:
3362+ raise RuntimeError("Profiles - Contact does not have Name")
3363+
3364+ # Check the user has a phone number
3365+ if profile_page.profile_user_phone_number.text is None:
3366+ raise RuntimeError("Profiles - Contact does not have valid Phone Number")
3367\ No newline at end of file
3368
3369=== added file 'telegram/autopilot/telegram/utilities.py'
3370--- telegram/autopilot/telegram/utilities.py 1970-01-01 00:00:00 +0000
3371+++ telegram/autopilot/telegram/utilities.py 2016-11-14 11:39:33 +0000
3372@@ -0,0 +1,36 @@
3373+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
3374+# Copyright 2016 Canonical
3375+#
3376+# This file is part of telegram-app.
3377+#
3378+# telegram-app is free software: you can redistribute it and/or modify it
3379+# under the terms of the GNU General Public License version 3, as published
3380+# by the Free Software Foundation.
3381+
3382+
3383+"""Telegram app helper functions"""
3384+
3385+from autopilot.input import Keyboard
3386+
3387+""" KEYBOARD UTILITIES """
3388+
3389+global mainKeyboard
3390+
3391+def enter_text_in_text_area(text_area, text):
3392+ #Assign keyboard type
3393+ mainKeyboard = Keyboard.create()
3394+
3395+ #Focus TextArea and begin typing
3396+ with mainKeyboard.focused_type(text_area) as kb:
3397+ kb.type(text)
3398+
3399+def enter_text_in_text_area_and_press_enter(text_area, text):
3400+ #Assign keyboard type
3401+ mainKeyboard = Keyboard.create()
3402+
3403+ #Focus TextArea and begin typing
3404+ with mainKeyboard.focused_type(text_area) as kb:
3405+ kb.type(text)
3406+
3407+ #Simulate 'Enter' key being pressed
3408+ mainKeyboard.press_and_release('Enter')
3409\ No newline at end of file

Subscribers

People subscribed via source and target branches

to status/vote changes: