blob: 314d452aebe29043566cfacff42bdf0f7618f31f [file] [log] [blame] [edit]
"""
Copyright 2013 Appurify, Inc
All rights reserved
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
To run tests:
from parent directory of tests:
python -m unittest tests.test_client
"""
import unittest
import json
import mock
import os
from appurify.client import AppurifyClient, AppurifyClientError
class TestObject(object):
pass
def mockRequestObj(response_obj, status_code=200):
r = TestObject()
r.headers = {'x-api-server-hostname': 'django-01'}
r.text = json.dumps(response_obj)
r.status_code = status_code
r.json = lambda: response_obj
return r
def mockRequestPost(url, data, files=None, verify=False, headers={'User-Agent': 'MockAgent'}):
if 'access_token/generate' in url:
return mockRequestObj({"meta": {"code": 200}, "response": {"access_token": "test_access_token", "ttl": 86400}})
if 'apps/upload' in url:
name = data.get('name', None)
return mockRequestObj({"meta": {"code": 200},
"response": {"_id_": None,
"uploaded_on": "2013-09-09T21:25:24Z",
"name": name,
"app_group_id": None,
"test_type": "test_test_type",
"size": None,
"app_group": "None",
"id": 12345,
"app_id": "test_app_id"}})
if 'tests/upload' in url:
return mockRequestObj({"meta": {"code": 200},
"response": {"uploaded_on": "2013-09-09T22:30:51Z",
"name": "use_bdd_tests.zip", "ttl": 86400,
"config": None,
"test_type": "uiautomation",
"test_id": "test_test_id",
"expired": False,
"id": 3456,
"size": 1326}})
if 'config/upload/' in url:
return mockRequestObj({"meta": {"code": 200},
"response": {"test_id": "test_test_id",
"config_id": 23456,
"conf_file": "appurify.conf"}})
if 'tests/run' in url:
return mockRequestObj({
"meta": {
"code": 200
},
"response": {
"id": 16282,
"test_type": "uiautomation",
"device_type": {
"device_type_id": 58,
"name": "5_NR",
"battery": False,
"brand": "iPhone",
"os_name": "iOS",
"os_version": "6.1.2",
"has_available_device": None,
"carrier": None,
"available_devices_count": None,
"busy_devices_count": None,
"all_devices_count": None,
"is_rooted": False,
"is_api": True,
"is_manual": False
},
"request_time": "2013-09-11T22:35:18.724Z",
"start_time": None,
"end_time": None,
"all_pass": False,
"run_id": "test_test_run_id",
"nbr_pass": None,
"nbr_fail": None,
"queued": True,
"app": 17967,
"version": {
"id": 17967,
"app": 7735,
"uploaded_on": "2013-09-11T22:35:18Z",
"description": None,
"size": 197072,
"icon_url": "/api/app/icon/?app_id=c5f361ebed16488dbf6b69be54f03e2c",
"app_id": "c5f361ebed16488dbf6b69be54f03e2c",
"app_type": "ios",
"web_app_url": None
},
"app_name": "use-bdd",
"device": "58 - iPhone 5_NR / iOS 6.1.2",
"source": 16177,
"config": {
"id": 1963,
"device": {
"id": 123,
"profiler": True,
"videocapture": True,
"import_photos": False,
"import_contacts": False,
"latitude": "37.777363",
"longitude": "-122.395894",
"packet_capture": True,
"free_memory": None,
"orientation": None,
"network": None
},
"framework": "{\"uiautomation\": {\"template\": \"Memory_Profiling_Template\"}}",
"test_timeout": 240,
"debug": False,
"keep_vm": False,
"device_types": [],
"vm_size": "small"
},
"status": "queueing",
"test_id": "test_test_id",
"app_id": "test_app_id",
"test_run_id": "test_test_run_id",
"queue_timeout_limit": 2
}
})
def mockRequestPostMulti(url, data, files=None, verify=False, headers={'User-Agent': 'MockAgent'}):
if 'tests/run' in url:
return mockRequestObj({
"meta": {
"code": 200
},
"response": {
"test_run_id": "test_test_run_id1,test_test_run_id2",
"test_id": "test_test_id",
"test_runs": [
{
"id": 16290,
"test_type": "uiautomation",
"device_type": {
"device_type_id": 58,
"name": "5_NR",
"battery": False,
"brand": "iPhone",
"os_name": "iOS",
"os_version": "6.1.2",
"has_available_device": None,
"carrier": None,
"available_devices_count": None,
"busy_devices_count": None,
"all_devices_count": None,
"is_rooted": False,
"is_api": True,
"is_manual": False
},
"request_time": "2013-09-12T22:01:48.594Z",
"start_time": None,
"end_time": None,
"all_pass": False,
"run_id": "test_test_run_id1",
"nbr_pass": None,
"nbr_fail": None,
"queued": True,
"app": 17975,
"version": {
"id": 17975,
"app": 7735,
"uploaded_on": "2013-09-12T21:59:07Z",
"description": None,
"size": 197072,
"icon_url": "/api/app/icon/?app_id=4858befdd9304984a171837c612746eb",
"app_id": "test_app_id",
"app_type": "ios",
"web_app_url": None
},
"app_name": "use-bdd",
"device": "58 - iPhone 5_NR / iOS 6.1.2",
"source": 16185,
"config": {
"id": 1971,
"device": {
"id": 123,
"profiler": True,
"videocapture": True,
"import_photos": False,
"import_contacts": False,
"latitude": "37.777363",
"longitude": "-122.395894",
"packet_capture": True,
"free_memory": None,
"orientation": None,
"network": None
},
"framework": "{\"uiautomation\": {\"template\": \"Memory_Profiling_Template\"}}",
"test_timeout": 240,
"debug": False,
"keep_vm": False,
"device_types": [],
"vm_size": "small",
"raw": "[uiautomation]\ntemplate=Memory_Profiling_Template\n\n[appurify]\nprofiler=1\npcap=1\nlatlng=37.777363,-122.395894\n\n"
},
"status": "queueing",
"test_id": "test_test_id",
"app_id": "test_app_id",
"test_run_id": "test_test_run_id1",
"device_type_id": 58,
"queue_timeout_limit": 2,
},
{
"id": 16291,
"test_type": "uiautomation",
"device_type": {
"device_type_id": 61,
"name": "5_NR",
"battery": False,
"brand": "iPhone",
"os_name": "iOS",
"os_version": "6.0.2",
"has_available_device": None,
"carrier": None,
"available_devices_count": None,
"busy_devices_count": None,
"all_devices_count": None,
"is_rooted": False,
"is_api": True,
"is_manual": False
},
"request_time": "2013-09-12T22:01:48.614Z",
"start_time": None,
"end_time": None,
"all_pass": False,
"run_id": "test_test_run_id2",
"nbr_pass": None,
"nbr_fail": None,
"queued": True,
"app": 17975,
"version": {
"id": 17975,
"app": 7735,
"uploaded_on": "2013-09-12T21:59:07Z",
"description": None,
"size": 197072,
"icon_url": "/api/app/icon/?app_id=4858befdd9304984a171837c612746eb",
"app_id": "test_app_id",
"app_type": "ios",
"web_app_url": None
},
"app_name": "use-bdd",
"device": "61 - iPhone 5_NR / iOS 6.0.2",
"source": 16185,
"config": {
"id": 1971,
"device": {
"id": 234,
"profiler": True,
"videocapture": True,
"import_photos": False,
"import_contacts": False,
"latitude": "37.777363",
"longitude": "-122.395894",
"packet_capture": True,
"free_memory": None,
"orientation": None,
"network": None
},
"framework": "{\"uiautomation\": {\"template\": \"Memory_Profiling_Template\"}}",
"test_timeout": 240,
"debug": False,
"keep_vm": False,
"device_types": [],
"vm_size": "small",
"raw": "[uiautomation]\ntemplate=Memory_Profiling_Template\n\n[appurify]\nprofiler=1\npcap=1\nlatlng=37.777363,-122.395894\n\n"
},
"status": "queueing",
"test_id": "test_test_id",
"app_id": "test_app_id",
"test_run_id": "test_test_run_id2",
"device_type_id": 61,
"queue_timeout_limit": 2,
}
],
"app_id": "test_app_id",
}
})
else:
raise Exception("Unrecognized url")
def mockRequestGet(url, params, verify=False, headers={'User-Agent': 'MockUserAgent'}):
if 'tests/check' in url:
if mockRequestGet.count <= 0:
mockRequestGet.count = mockRequestGet.count + 1
return mockRequestObj({"meta": {"code": 200},
"response": {"status": "in-progress",
"test_run_id": "test_test_run_id",
"test_config": "[uiautomation]\n\n[appurify]\nprofiler=1\npcap=1\n",
"device_type": "58 - iPhone 5_NR / iOS 6.1.2",
"device_type_id": 58}})
elif mockRequestGet.exception:
mockRequestGet.count = mockRequestGet.count + 1
return mockRequestObj({"meta": {"code": 200},
"response": {"status": "complete",
"detailed_status": "exception",
"results": {"exception": "-9999: Other exception",
"errors": None,
"url": "http://localhost/resource/tests/result/?run_id=dummy_test_run_id",
"number_passes": mockRequestGet.passes,
"number_fails": mockRequestGet.fails,
"pass": mockRequestGet.pass_val,
"output": ""},
"test_run_id": "test_test_run_id",
"device_type": "58 - iPhone 5_NR / iOS 6.1.2",
"device_type_id": 58}})
else:
mockRequestGet.count = mockRequestGet.count + 1
return mockRequestObj({"meta": {"code": 200},
"response": {"status": "complete",
"test_config": "[test_type]\nconfig",
"results": {"exception": None,
"errors": "",
"url": "http://localhost/resource/tests/result/?run_id=dummy_test_run_id",
"number_passes": mockRequestGet.passes,
"number_fails": mockRequestGet.fails,
"pass": mockRequestGet.pass_val,
"output": "test_run_output"},
"test_run_id": "test_test_run_id",
"device_type": "58 - iPhone 5_NR / iOS 6.1.2",
"device_type_id": 58}})
mockRequestGet.count = 0
mockRequestGet.passes = 1
mockRequestGet.fails = 1
mockRequestGet.exception = 0
mockRequestGet.pass_val = False
def mockRequestGetPrimaryException(url, params, verify=False, headers={'User-Agent': 'MockUserAgent'}):
raise Exception("Mock Syntax Error")
class TestAuth(unittest.TestCase):
def setUp(self):
self.client = AppurifyClient(api_key="test_key", api_secret="test_secret")
@mock.patch("requests.post", mockRequestPost)
def testGetAccessToken(self):
client = AppurifyClient(api_key="test_key", api_secret="test_secret")
client.refreshAccessToken()
access_token = client.access_token
self.assertEqual(access_token, "test_access_token", "Should return proper access token on post")
def testGetAccessTokenPrePop(self):
client = AppurifyClient(access_token="Already_Set")
client.refreshAccessToken()
access_token = client.access_token
self.assertEqual(access_token, "Already_Set", "Should return access token when one is provided")
def testNoAuth(self):
client = AppurifyClient()
with self.assertRaises(AppurifyClientError):
""" Should error out on no auth data """
client.refreshAccessToken()
class TestUpload(unittest.TestCase):
@mock.patch("requests.post", mockRequestPost)
def testUploadAppNoSource(self):
client = AppurifyClient(access_token="authenticated", test_type='ios_webrobot')
app_id = client.uploadApp()
self.assertEqual(app_id, "test_app_id", "Should properly fetch web robot for app id")
@mock.patch("requests.post", mockRequestPost)
def testUploadAppSource(self):
client = AppurifyClient(access_token="authenticated", app_src=__file__, app_src_type='raw', test_type='calabash', name="test_name")
app_id = client.uploadApp()
self.assertEqual(app_id, "test_app_id", "Should properly fetch web robot for app id")
@mock.patch("requests.post", mockRequestPost)
def testUploadAppNoSourceError(self):
client = AppurifyClient(access_token="authenticated", app_src_type='raw', test_type='calabash')
with self.assertRaises(AppurifyClientError):
client.uploadApp()
@mock.patch("requests.post", mockRequestPost)
def testUploadTestNoSource(self):
client = AppurifyClient(access_token="authenticated", test_type='ios_webrobot')
app_id = client.uploadTest('test_app_id')
self.assertEqual(app_id, "test_test_id", "Should properly fetch web robot for app id")
@mock.patch("requests.post", mockRequestPost)
def testUploadTest(self):
client = AppurifyClient(access_token="authenticated", test_src=__file__, test_type="uiautomation", test_src_type='raw')
test_id = client.uploadTest('test_app_id')
self.assertEqual(test_id, "test_test_id", "Should properly fetch web robot for app id")
@mock.patch("requests.post", mockRequestPost)
def testUploadTestNoSourceError(self):
client = AppurifyClient(access_token="authenticated", test_type='uiautomation')
with self.assertRaises(AppurifyClientError):
app_id = client.uploadTest('test_app_id')
@mock.patch("requests.post", mockRequestPost)
def testUploadConfig(self):
client = AppurifyClient(access_token="authenticated", test_type="ios_webrobot")
config_id = client.uploadConfig("test_id", config_src=__file__)
self.assertEqual(config_id, 23456, "Should properly fetch uploaded config id")
def testPrintConfig(self):
client = AppurifyClient(access_token="authenticated", test_type="ios_webrobot")
config = [{
"id": 1963,
"device": {
"id": 123,
"profiler": True,
"videocapture": True,
},
"framework": "{\"uiautomation\": {\"template\": \"Memory_Profiling_Template\"}}",
"test_timeout": 240,
"debug": False,
"keep_vm": False,
"device_types": [],
"vm_size": "small"
}]
client.printConfigs(config)
class TestRun(unittest.TestCase):
@mock.patch("requests.post", mockRequestPost)
def testRunTestSingle(self):
client = AppurifyClient(access_token="authenticated")
test_run_id, queue_timeout_limit, configs = client.runTest("app_id", "test_test_id")
self.assertEqual(test_run_id, "test_test_run_id", "Should get test_run_id when executing run")
self.assertEqual(len(configs), 1, "Should get config back for test run")
self.assertEqual(configs[0]['device']['id'], 123, "Sanity check parameters")
@mock.patch("requests.post", mockRequestPostMulti)
def testRunTestMulti(self):
client = AppurifyClient(access_token="authenticated")
test_run_id, queue_timeout_limit, configs = client.runTest("app_id", "test_test_id")
self.assertEqual(test_run_id, "test_test_run_id1,test_test_run_id2", "Should get test_run_ids when executing run")
self.assertEqual(len(configs), 2, "Should get config back for test run")
self.assertEqual(configs[0]['device']['id'], 123, "Sanity check parameters")
@mock.patch("requests.get", mockRequestGet)
def testPollTestResult(self):
mockRequestGet.count = 0
client = AppurifyClient(access_token="authenticated", timeout_sec=2, poll_every=0.1)
test_status_response = client.pollTestResult("test_test_run_id", 2)
self.assertEqual(test_status_response['status'], "complete", "Should poll until complete")
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testMainServerException(self):
mockRequestGet.count = 0
mockRequestGet.passes = 0
mockRequestGet.fails = 0
mockRequestGet.exception = 1
mockRequestGet.pass_val = False
client = AppurifyClient(api_key="test_key", api_secret="test_secret", test_type="uiautomation",
app_src=__file__, app_src_type='raw',
test_src=__file__, test_src_type='raw',
timeout_sec=2, poll_every=0.1)
result_code = client.main()
self.assertEqual(result_code, 7, "Main should execute and return exception code")
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testMainFail(self):
mockRequestGet.count = 0
mockRequestGet.passes = 1
mockRequestGet.fails = 1
mockRequestGet.exception = 0
mockRequestGet.pass_val = False
client = AppurifyClient(api_key="test_key", api_secret="test_secret", test_type="uiautomation",
app_src=__file__, app_src_type='raw',
test_src=__file__, test_src_type='raw',
timeout_sec=2, poll_every=0.1)
result_code = client.main()
self.assertEqual(result_code, 1, "Main should execute and return fail code")
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testMainPass(self):
mockRequestGet.count = 0
mockRequestGet.passes = 2
mockRequestGet.fails = 0
mockRequestGet.exception = 0
mockRequestGet.pass_val = True
client = AppurifyClient(api_key="test_key", api_secret="test_secret", test_type="uiautomation",
app_src=__file__, app_src_type='raw',
test_src=__file__, test_src_type='raw',
timeout_sec=2, poll_every=0.1)
result_code = client.main()
self.assertEqual(result_code, 0, "Main should execute and return pass code")
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testMainPassUrl(self):
mockRequestGet.count = 0
mockRequestGet.passes = 2
mockRequestGet.fails = 0
mockRequestGet.exception = 0
mockRequestGet.pass_val = True
client = AppurifyClient(api_key="test_key", api_secret="test_secret", test_type="ios_webrobot",
app_src=None,
test_src=None,
url="www.yahoo.com",
timeout_sec=2, poll_every=0.1)
result_code = client.main()
self.assertEqual(result_code, 0, "Main should execute and return pass code")
@mock.patch("requests.get", mockRequestGet)
def testDefaultPollTimeout(self):
old_env = os.environ.get('APPURIFY_API_TIMEOUT', None)
try:
os.environ['APPURIFY_API_TIMEOUT'] = '0.2'
mockRequestGet.count = -20
client = AppurifyClient(access_token="authenticated", poll_every=0.1)
with self.assertRaises(AppurifyClientError):
client.pollTestResult("test_test_run_id", 0.2)
finally:
if old_env:
os.environ['APPURIFY_API_TIMEOUT'] = str(old_env)
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testDefaultPollTimeoutCode(self):
old_env = os.environ.get('APPURIFY_API_TIMEOUT', None)
try:
os.environ['APPURIFY_API_TIMEOUT'] = '0.2'
mockRequestGet.count = -20
client = AppurifyClient(api_key="test_key", api_secret="test_secret", test_type="ios_webrobot",
app_src=None,
test_src=None,
url="www.yahoo.com",
poll_every=0.1)
result_code = client.main()
self.assertEqual(result_code, 3, "Main should execute and return error code with default timeout")
finally:
if old_env:
os.environ['APPURIFY_API_TIMEOUT'] = str(old_env)
@mock.patch("requests.get", mockRequestGet)
def testPollTimeout(self):
mockRequestGet.count = -20
client = AppurifyClient(access_token="authenticated", timeout_sec=0.2, poll_every=0.1)
with self.assertRaises(AppurifyClientError):
client.pollTestResult("test_test_run_id", 0.2)
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testPollTimeoutCode(self):
mockRequestGet.count = -20
client = AppurifyClient(api_key="test_key", api_secret="test_secret", test_type="ios_webrobot",
app_src=None,
test_src=None,
url="www.yahoo.com",
timeout_sec=0.2,
poll_every=0.1)
result_code = client.main()
self.assertEqual(result_code, 3, "Main should execute and return error code")
@mock.patch("requests.post", mockRequestPost)
@mock.patch("requests.get", mockRequestGet)
def testGetExceptionExitCode(self):
mockRequestGet.count = -20
client = AppurifyClient(access_token="authenticated", timeout_sec=0.2, poll_every=0.1)
self.assertEqual(client.getExceptionExitCode([{"exception": "4007: Error installing the app: file does not contain AndroidManifest.xml\n (1)"}]), 5, "Should return correct exit code for matching exception")
self.assertEqual(client.getExceptionExitCode([{"exception": "-9999: no match anything"}]), 7, "Should return correct exit code for no exception")