From f6af1ef74ef3639e56903ed25a2854118ff9023f Mon Sep 17 00:00:00 2001 From: Remek Zajac Date: Wed, 3 Dec 2014 15:42:19 +0000 Subject: [PATCH 1/3] Adding the facility to await (poll) a scheduled test run --- testdroid/__init__.py | 46 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/testdroid/__init__.py b/testdroid/__init__.py index 42a68aa..918d04d 100755 --- a/testdroid/__init__.py +++ b/testdroid/__init__.py @@ -75,6 +75,8 @@ class Testdroid: token_expiration_time = None # Buffer size used for downloads download_buffer_size = 65536 + # polling interval when awaiting for test run completion + polling_interval_mins = 10 """ Simple constructor, defaults against cloud.testdroid.com """ @@ -148,7 +150,7 @@ def get_token(self): self.access_token = reply['access_token'] self.refresh_token = reply['refresh_token'] - self.token_expiration_time = time.time() + reply['expires_in'] + self.token_expiration_time = time.time() + reply['expires_in'] return self.access_token """ Helper method for getting necessary headers to use for API calls, including authentication @@ -327,23 +329,55 @@ def start_test_run(self, project_id, device_group_id=None, device_model_ids=None print "Unable to set used device group to %s for project %s" % (device_group_id, project_id) sys.exit(1) print "Starting test run on project %s \"%s\" using device group %s \"%s\"" % (project['id'], project['name'], device_group['id'], device_group['displayName']) - + else: payload={'usedDeviceIds[]': device_model_ids} print "Starting test run on project %s \"%s\" using device models ids %s \"%s\"" % (project['id'], project['name'], device_model_ids) - + # Start run path = "/users/%s/projects/%s/runs" % ( me['id'], project_id ) reply = self.post(path=path, payload=payload) print "Test run id: %s" % reply['id'] print "Name: %s" % reply['displayName'] + return reply['id'] + + + """ Start a test run on a device group and wait for completion + """ + def start_wait_test_run(self, project_id, device_group_id=None, device_model_ids=None): + self.wait_test_run( + project_id, self.start_test_run(project_id, device_group_id, device_model_ids) + ) + + """ Awaits completion of the given test run + """ + def wait_test_run(self, project_id, test_run_id): + if test_run_id: + print "Awaiting completion of test run with id %s. Will wait forever polling every %smins." % (test_run_id, Testdroid.polling_interval_mins) + while True: + time.sleep(Testdroid.polling_interval_mins*60) + self.get_token() #in case it expired + testRunStatus = self.get_test_run(project_id, test_run_id) + if testRunStatus and testRunStatus.has_key('state'): + if testRunStatus['state'] == "FINISHED": + print "The test run with id: %s is FINISHED" % test_run_id + break + elif testRunStatus['state'] == "WAITING": + print "[%s] The test run with id: %s is still in progress..." % (time.strftime("%H:%M:%S"), test_run_id) + continue + + print "Couldn't establish the state of the test run with id: %s. Aborting" % test_run_id + print testRunStatus + sys.exit(1) + + return test_run_id """ Start device sessions """ def start_device_session(self, device_model_id): payload={'deviceModelId':device_model_id} return self.post("me/device-sessions", payload) - + """ Stop device session """ def stop_device_session(self, device_session_id): @@ -427,6 +461,8 @@ def format_epilog(self, formatter): upload-test Upload test file to project upload-data Upload additional data file to project start-test-run Start a test run + start-wait-test-run Start a test run and await completion (polling) + wait-test-run Await completion (polling) of the test run test-runs Get test runs for a project test-run Get test run details device-runs Get device runs for a test run @@ -458,6 +494,8 @@ def get_commands(self): "upload-test": self.upload_test_file, "upload-data": self.upload_data_file, "start-test-run": self.start_test_run, + "start-wait-test-run":self.start_wait_test_run, + "wait-test-run":self.wait_test_run, "test-run": self.get_test_run, "test-runs": self.print_project_test_runs, "device-runs": self.get_device_runs, From 2c166b1d6440aa046a620bdc3cc1854ca32f1b44 Mon Sep 17 00:00:00 2001 From: Remek Zajac Date: Wed, 3 Dec 2014 17:02:33 +0000 Subject: [PATCH 2/3] Adding workaround for the token expiry problem (see comment inside the code) --- testdroid/__init__.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/testdroid/__init__.py b/testdroid/__init__.py index 918d04d..151063f 100755 --- a/testdroid/__init__.py +++ b/testdroid/__init__.py @@ -151,6 +151,7 @@ def get_token(self): self.access_token = reply['access_token'] self.refresh_token = reply['refresh_token'] self.token_expiration_time = time.time() + reply['expires_in'] + return self.access_token """ Helper method for getting necessary headers to use for API calls, including authentication @@ -356,14 +357,23 @@ def wait_test_run(self, project_id, test_run_id): print "Awaiting completion of test run with id %s. Will wait forever polling every %smins." % (test_run_id, Testdroid.polling_interval_mins) while True: time.sleep(Testdroid.polling_interval_mins*60) - self.get_token() #in case it expired + self.access_token = None #WORKAROUND: access token thinks it's still valid, + # > token valid for another 633.357925177 + #whilst this happens: + # > Couldn't establish the state of the test run with id: 72593732. Aborting + # > {u'error_description': u'Invalid access token: b3e62604-9d2a-49dc-88f5-89786ff5a6b6', u'error': u'invalid_token'} + + self.get_token() #in case it expired testRunStatus = self.get_test_run(project_id, test_run_id) if testRunStatus and testRunStatus.has_key('state'): if testRunStatus['state'] == "FINISHED": - print "The test run with id: %s is FINISHED" % test_run_id + print "The test run with id: %s has FINISHED" % test_run_id break elif testRunStatus['state'] == "WAITING": - print "[%s] The test run with id: %s is still in progress..." % (time.strftime("%H:%M:%S"), test_run_id) + print "[%s] The test run with id: %s is awaiting to be scheduled" % (time.strftime("%H:%M:%S"), test_run_id) + continue + elif testRunStatus['state'] == "RUNNING": + print "[%s] The test run with id: %s is running" % (time.strftime("%H:%M:%S"), test_run_id) continue print "Couldn't establish the state of the test run with id: %s. Aborting" % test_run_id From 37d3ae3448c8b4db5580778b4187df4423fdf1d7 Mon Sep 17 00:00:00 2001 From: Remek Zajac Date: Wed, 10 Dec 2014 17:24:48 +0000 Subject: [PATCH 3/3] Add the download-on-finish function. Otherwise the script output needs parsing. --- testdroid/__init__.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/testdroid/__init__.py b/testdroid/__init__.py index 151063f..8fcb705 100755 --- a/testdroid/__init__.py +++ b/testdroid/__init__.py @@ -346,9 +346,16 @@ def start_test_run(self, project_id, device_group_id=None, device_model_ids=None """ Start a test run on a device group and wait for completion """ def start_wait_test_run(self, project_id, device_group_id=None, device_model_ids=None): - self.wait_test_run( - project_id, self.start_test_run(project_id, device_group_id, device_model_ids) - ) + test_run_id = self.start_test_run(project_id, device_group_id, device_model_ids) + self.wait_test_run(project_id, test_run_id) + return test_run_id + + + """ Start a test run on a device group, wait for completion and download results + """ + def start_wait_download_test_run(self, project_id, device_group_id=None, device_model_ids=None): + test_run_id = self.start_wait_test_run(project_id, device_group_id, device_model_ids) + self.download_test_run(project_id, test_run_id) """ Awaits completion of the given test run """ @@ -380,7 +387,6 @@ def wait_test_run(self, project_id, test_run_id): print testRunStatus sys.exit(1) - return test_run_id """ Start device sessions """ @@ -471,7 +477,9 @@ def format_epilog(self, formatter): upload-test Upload test file to project upload-data Upload additional data file to project start-test-run Start a test run - start-wait-test-run Start a test run and await completion (polling) + start-wait-download-test-run + Start a test run, await completion (polling) and + download results wait-test-run Await completion (polling) of the test run test-runs Get test runs for a project test-run Get test run details @@ -504,7 +512,7 @@ def get_commands(self): "upload-test": self.upload_test_file, "upload-data": self.upload_data_file, "start-test-run": self.start_test_run, - "start-wait-test-run":self.start_wait_test_run, + "start-wait-download-test-run":self.start_wait_download_test_run, "wait-test-run":self.wait_test_run, "test-run": self.get_test_run, "test-runs": self.print_project_test_runs,