Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8a41694
Bump version to 0.1.8.dev from 0.1.7
spedepekka Jan 16, 2015
8021cba
Merge branch 'master' into devel
spedepekka Jan 16, 2015
faad260
Merge pull request #14 from spedepekka/devel
spedepekka Jan 16, 2015
b1df54e
Merge branch 'master' into devel
spedepekka Jan 19, 2015
4de9138
Merge pull request #18 from spedepekka/devel
spedepekka Jan 19, 2015
bdf4fc0
Merge pull request #3 from bitbar/devel
Feb 2, 2015
91f39ad
Unlimited device run & screenshot downloads
Feb 2, 2015
e29a6df
Add feature 'Print available free devices'
Feb 2, 2015
e5153c1
Fix logger problem caused by missing FORMAT definition
Feb 2, 2015
9b4bb8f
Correct help text for screenshot downloads
Feb 2, 2015
56a7f8a
Fix typo from authors field
Feb 3, 2015
ff7c9a3
Add check for predefined logger FORMAT
Feb 5, 2015
7688075
Refactor test run download to download all available files
Feb 5, 2015
7940a28
Do not write limit to path, use payload instead
spedepekka Jan 23, 2015
7f1178c
Improve README
spedepekka Feb 5, 2015
3421204
Merge pull request #20 from spedepekka/devel
Feb 5, 2015
4489212
Merge devel to Teppo's PR 19
spedepekka Feb 5, 2015
326c4f3
Merge pull request #4 from spedepekka/teppo
Feb 5, 2015
49aed0c
Fix amp
spedepekka Feb 5, 2015
31c6141
Get all device runs
spedepekka Feb 5, 2015
146a278
Merge pull request #21 from spedepekka/devel
spedepekka Feb 5, 2015
ec5c23c
Merge pull request #19 from teppomalinen/master
spedepekka Feb 5, 2015
e5f7c58
All resources unlimited
spedepekka Feb 6, 2015
7e5948b
Update CHANGELOG
spedepekka Feb 6, 2015
973b2ce
Bump version from 0.1.9.dev to 0.1.9
spedepekka Feb 6, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
0.1.9
* Fix Logger problem, caused by missing FORMAT definition
* Add feature 'Print available free devices'
* Set unlimited device run & screenshot downloads
* Correct help text for screenshots download
* Refactor test run download feature to download all files available for the test run
* Do not limit number of results

0.1.8
* Fix file download for Linux and Mac machines.

Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
Python client for Testdroid Cloud APIv2
=======================================

Dependencies
-----

For Linux installatin you need Python dev package.

Ubuntu
`sudo apt-get install python-dev`

Command line
-----

Install it with:
`sudo pip install testdroid`

Upgrade it with:
`sudo pip install testdroid --upgrade`

Usage
-----

Expand Down Expand Up @@ -45,3 +56,8 @@ Usage
`testdroid`


Troubleshooting
-----

If you see Pillow error messages on Linux you are most likely missing python-dev, see dependencies.

4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from setuptools import setup, find_packages
import sys, os

version = '0.1.8'
version = '0.1.9'

setup(name='testdroid',
version=version,
Expand All @@ -13,7 +13,7 @@
'Topic :: Software Development',
'Intended Audience :: Developers'], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='testdroid rest api client',
author='Henri Kivelä <henri.kivela@bitbar.com>, Sakari Rautiainen <sakari.rautiainen@bitbar.com>, Teppo Malinen <teppo.malinen@bitbar.com, Jarno Tuovinen <jarno.tuovinen@bitbar.com>',
author='Henri Kivelä <henri.kivela@bitbar.com>, Sakari Rautiainen <sakari.rautiainen@bitbar.com>, Teppo Malinen <teppo.malinen@bitbar.com>, Jarno Tuovinen <jarno.tuovinen@bitbar.com>',
author_email='info@bitbar.com',
url='http://www.testdroid.com',
license='Apache License v2.0',
Expand Down
130 changes: 88 additions & 42 deletions testdroid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
from collections import namedtuple
from datetime import datetime

FORMAT = '%(message)s'
__version__ = '0.1.8'
logging.basicConfig(format=FORMAT)
__version__ = '0.1.9'
try:
logging.basicConfig(format=FORMAT)
except Exception, e:
print "Warning: %s. Using FORMAT='%s(message)s.'" % (e, "%s")
logging.basicConfig(format="%(message)s")

logger = logging.getLogger('testdroid')
logger.setLevel(logging.INFO)

Expand Down Expand Up @@ -238,20 +242,53 @@ def get_me(self):

""" Returns list of device groups
"""
def get_device_groups(self):
return self.get("me/device-groups")
def get_device_groups(self, limit=0):
return self.get("me/device-groups", payload = {'limit': limit})

""" Returns list of devices
"""
def get_devices(self, limit=0):
return self.get("devices?limit=%s" % (limit))
return self.get(path = "devices", payload = {'limit': limit})

""" Print device groups
"""
def print_device_groups(self):
for device_group in self.get_device_groups()['data']:
def print_device_groups(self, limit=0):
for device_group in self.get_device_groups(limit)['data']:
print "%s %s %s %s devices" % (str(device_group['id']).ljust(12), device_group['displayName'].ljust(30), device_group['osType'].ljust(10), device_group['deviceCount'])

""" Print available free Android devices
"""
def print_available_free_android_devices(self, limit=0):
print ""
print "Available Free Android Devices"
print "------------------------------"

for device in self.get_devices(limit)['data']:
if device['creditsPrice'] == 0 and device['locked'] == False and device['osType'] == "ANDROID":
print device['displayName']

print ""

""" Print available free iOS devices
"""
def print_available_free_ios_devices(self, limit=0):
print ""
print "Available Free iOS Devices"
print "--------------------------"

for device in self.get_devices(limit)['data']:
if device['creditsPrice'] == 0 and device['locked'] == False and device['osType'] == "IOS":
print device['displayName']

print ""

""" Print available free devices
"""
def print_available_free_devices(self, limit=0):
self.print_available_free_android_devices(limit)
self.print_available_free_ios_devices(limit)


""" Create a project
"""
def create_project(self, project_name, project_type):
Expand All @@ -269,8 +306,8 @@ def delete_project(self, project_id):

""" Returns projects for user
"""
def get_projects(self):
return self.get("me/projects")
def get_projects(self, limit=0):
return self.get(path="me/projects", payload = {'limit': limit})

""" Returns a single project
"""
Expand All @@ -279,11 +316,11 @@ def get_project(self, project_id):

""" Print projects
"""
def print_projects(self):
def print_projects(self, limit=0):
me = self.get_me()
print "Projects for %s <%s>:" % (me['name'], me['email'])
print
for project in self.get_projects()['data']:
for project in self.get_projects(limit)['data']:
print "%s %s \"%s\"" % (str(project['id']).ljust(10), project['type'].ljust(15), project['name'])

""" Upload application file to project
Expand Down Expand Up @@ -437,12 +474,12 @@ def stop_device_session(self, device_session_id):

""" Get all test runs for a project
"""
def get_project_test_runs(self, project_id, limit=20):
return self.get("me/projects/%s/runs?limit=%s" % (project_id, limit))
def get_project_test_runs(self, project_id, limit=0):
return self.get(path = "me/projects/%s/runs" % (project_id), payload = {'limit': limit})

""" Print test runs of a project to console
"""
def print_project_test_runs(self, project_id, limit=20):
def print_project_test_runs(self, project_id, limit=0):
test_runs = self.get_project_test_runs(project_id, limit)['data']
for test_run in test_runs:
print "%s %s %s %s" % (str(test_run['id']).ljust(10), ts_format(test_run['createTime']), test_run['displayName'].ljust(30), test_run['state'])
Expand All @@ -454,43 +491,50 @@ def get_test_run(self, project_id, test_run_id):

""" Return device runs for a project
"""
def get_device_runs(self, project_id, test_run_id, limit=1000):
return self.get("me/projects/%s/runs/%s/device-runs?limit=%s" % (project_id, test_run_id, limit))
def get_device_runs(self, project_id, test_run_id, limit=0):
return self.get(path = "me/projects/%s/runs/%s/device-runs" % (project_id, test_run_id), payload = {'limit': limit})

""" Downloads screenshots list for a device run
"""
def get_device_run_screenshots_list(self, project_id, test_run_id, device_run_id):
return self.get("me/projects/%s/runs/%s/device-runs/%s/screenshots" % (project_id, test_run_id, device_run_id))
def get_device_run_screenshots_list(self, project_id, test_run_id, device_run_id, limit=0):
return self.get("me/projects/%s/runs/%s/device-runs/%s/screenshots" % (project_id, test_run_id, device_run_id), payload = {'limit': limit})

""" Downloads test run results to a directory hierarchy
""" Downloads test run files to a directory hierarchy
"""
def download_test_run(self, project_id, test_run_id):
test_run = self.get_test_run(project_id, test_run_id)
device_runs = self.get_device_runs(project_id, test_run_id)
logger.info("Test run %s: \"%s\" has %s device runs:" % (test_run['id'], test_run['displayName'], len(device_runs['data'])))
for device_run in device_runs['data']:
logger.info("%s \"%s\" %s" % (device_run['id'], device_run['device']['displayName'], device_run['currentState']['status']))

logger.info("");
logger.info("")
logger.info("Test run %s: \"%s\" has %s device runs:" % (test_run['id'], test_run['displayName'], len(device_runs['data'])))

for device_run in device_runs['data']:
if device_run['currentState']['status'] == "SUCCEEDED":
directory = "%s-%s/%d-%s" % (test_run['id'], test_run['displayName'], device_run['id'], device_run['device']['displayName'])

filenames = ['junit.xml', 'logs', 'result-data.zip']

for filename in filenames:
full_path = "%s/%s" % (directory, filename)
if not os.path.exists(directory):
os.makedirs(directory)
url = "me/projects/%s/runs/%d/device-runs/%d/%s" % (project_id, test_run['id'], device_run['id'], filename)

prog = DownloadProgressBar()
self.download(url, full_path, callback=lambda pos, total: prog.update(int(pos), int(total)))
print

run_status = device_run['currentState']['status']
logger.info("")
logger.info("%s \"%s\" %s" % (device_run['id'], device_run['device']['displayName'], run_status))

if run_status in ("SUCCEEDED", "FAILED"):
directory = "%s-%s/%d-%s" % (test_run_id, test_run['displayName'], device_run['id'], device_run['device']['displayName'])
session_id = device_run['deviceSessionId']
files = self.get("me/projects/%s/runs/%s/device-sessions/%s/output-file-set/files" % (project_id, test_run_id, session_id))
for file in files['data']:
if file['state'] == "READY":
full_path = "%s/%s" % (directory, file['name'])
if not os.path.exists(directory):
os.makedirs(directory)

url = "me/files/%s/file" % (file['id'])
prog = DownloadProgressBar()
self.download(url, full_path, callback=lambda pos, total: prog.update(int(pos), int(total)))
print
else:
logger.info("File %s is not ready" % file['name'])
if( len(files['data']) == 0 ):
logger.info("No files to download")
logger.info("")
else:
logger.info("Device %s has not finished - skipping" % device_run['device']['displayName'])
logger.info("Device run is not ended - Skipping file downloads")
logger.info("")

""" Downloads test run screenshots
"""
Expand Down Expand Up @@ -547,6 +591,7 @@ def format_epilog(self, formatter):
Commands:

me Get user details
available-free-devices Print list of currently available free devices
device-groups Get list of your device groups
create-project <name> <type> Create a project
Type is one of:
Expand Down Expand Up @@ -580,9 +625,9 @@ def format_epilog(self, formatter):
current directory in a structure:
[test-run-id]/[device-run-id]-[device-name]/files...
download-test-screenshots <project-id> <test-run-id>
Download test run data. Data will be downloaded to
Download test run screenshots. Screenshots will be downloaded to
current directory in a structure:
[test-run-id]/[device-run-id]-[device-name]/files...
[test-run-id]/[device-run-id]-[device-name]/screenshots/...

"""
parser = MyParser(usage=usage, description=description, epilog=epilog, version="%s %s" % ("%prog", __version__))
Expand All @@ -602,6 +647,7 @@ def get_commands(self):
commands = {
"me": self.get_me,
"device-groups": self.print_device_groups,
"available-free-devices": self.print_available_free_devices,
"projects": self.print_projects,
"create-project": self.create_project,
"delete-project": self.delete_project,
Expand Down