AWS Device Farmからテスト実行結果を取得するPythonスクリプト+aws cliで書いてみた

# 動機
AWS Device FarmのManagement Consoleでは、テスト中に採取したスクリーンショットの順番が保持されないようなので、ちょっと不便
uiautomatorに特化した問題かも。

ソースは、 [AWS Glacierのファイルを通常S3に戻すためのPythonスクリプトを書きました](http://wwld.jp/2015/01/08/amazoncli-s3.html)を全面的に参考にさせていただきました。ありがとうございます。


# 前提
1. Windows
1. AWS CLI(の最新版)がインストールされていること。(最新版でないと取得できない属性あり。ただこのロジックには関係ないが。)
1. Python 3.4
2. [curl](http://curl.haxx.se/download.html) Win32-GenericのDaren Owenさんの7zipアーカイブを使用


# ソース
```GetTEstReusltFromAWSDeviceFarm.py
# -*- coding:utf-8 -*-
import subprocess 
import json
import os

# device farmのregion名を指定
region = 'us-west-2'

devicefarm_project_arn = 'arn:xxxxxxxxx'

# runのARNを指定
# 何も入力しないとdevicefarm_project_arnで指定したプロジェクトのすべてのrunを取得
# ただしrun数が多かった場合の継続には未対応
devicefarm_run_arn = ''

def result2str(result):
    if(result == "PASSED"):
        resultstr = "o"
    elif(result == "FAILED"):
        resultstr = "x"
    else:
        resultstr = "="
    return resultstr

def output_file(filename,str):
    f = open(filename, 'w')
    f.write(str)
    f.close()

def list_runs(project_arn):
    list_runs_cmd = ('aws devicefarm list-runs '
                    ' --arn "{0}"' )

    if region != '':
        list_runs_cmd += ' --region "{0}"'.format(region)

    list_runs_cmd = list_runs_cmd.format(project_arn)

    print('-' * 80)
    print(list_runs_cmd)

    json_str_runs = subprocess.check_output(list_runs_cmd , shell=True)
    json_str_runs = json_str_runs.decode('cp932')
    json_obj_runs = json.loads(json_str_runs)
    run_count = 0

    for run in json_obj_runs['runs']:
        list_jobs(run,run_count)
        run_count = run_count + 1
        
    os.chdir("..")

def list_jobs(run,run_count):
    run_arn = run['arn']
    run_name = run['name']

    print("  run={0} {1} {2}".format(result2str(run['result']),run_arn, run_name ))
    foldername = "{0:0>5}_{1}_{2}".format(run_count,result2str(run['result']),run_name)
    os.mkdir(foldername)
    os.chdir(foldername)

    list_jobs_cmd = ('aws devicefarm list-jobs'
                ' --arn "{0}"' )

    if region != '':
        list_jobs_cmd += ' --region "{0}"'.format(region)

    list_jobs_cmd = list_jobs_cmd.format(run_arn)
#    print('-' * 80)
    print("  " + list_jobs_cmd)

    json_str_jobs = subprocess.check_output(list_jobs_cmd, shell=True)
    json_str_jobs = json_str_jobs.decode('cp932')
    json_obj_jobs = json.loads(json_str_jobs)
    job_count = 0
    
    for job in json_obj_jobs['jobs']:
        list_suites(job,job_count)
        job_count = job_count + 1
    os.chdir("..")


def list_suites(job,job_count):
    job_arn = job['arn']
    job_name = job['name']
    job_device = job['device']['name']
    job_device_width = job['device']['resolution']['width']
    job_device_height = job['device']['resolution']['height']
    job_device_memory = job['device']['memory']
    job_device_os = job['device']['os']
    job_device_manufacturer = job['device']['manufacturer']
    job_device_model = job['device']['model']
    job_device_image = job['device']['image']
    job_device_memory = job['device']['memory']
    job_device_cpu_arch = job['device']['cpu']['architecture']
    job_device_cpu_clock = job['device']['cpu']['clock']
    job_device_form = job['device']['formFactor']
    job_device_heapSize = job['device']['heapSize']
    job_device_platform = job['device']['platform']
    print("    job={0} {1} {2}".format(result2str(job['result']),job_name,job_device))
    foldername = "{0:0>5}_{1}_{2}".format(job_count,result2str(job['result']),job_name)
    os.mkdir(foldername)
    os.chdir(foldername)
    
    output_file(foldername + ".json", json.dumps(job, indent=4))

    list_suites_cmd = ('aws devicefarm list-suites'
                ' --arn "{0}"' )

    if region != '':
        list_suites_cmd += ' --region "{0}"'.format(region)

    list_suites_cmd = list_suites_cmd.format(job_arn)
    json_str_suites = subprocess.check_output(list_suites_cmd, shell=True)
    json_str_suites = json_str_suites.decode('cp932')
    json_obj_suites = json.loads(json_str_suites)
    suite_count = 0
   
    for suite in json_obj_suites['suites']:
        list_tests(suite,suite_count)
        suite_count = suite_count + 1
        
    os.chdir("..")

def list_tests(suite,suite_count):
    suite_arn = suite['arn']
    suite_name = suite['name']
    print("      suite_name={0} {1}".format(result2str(suite['result']),suite_name))
    foldername = "{0:0>5}_{1}_{2}".format(suite_count,result2str(suite['result']),suite_name)
    os.mkdir(foldername)
    os.chdir(foldername)

    list_tests_cmd = ('aws devicefarm list-tests'
                ' --arn "{0}"' )

    if region != '':
        list_tests_cmd += ' --region "{0}"'.format(region)

    list_tests_cmd = list_tests_cmd.format(suite_arn)
    json_str_tests = subprocess.check_output(list_tests_cmd, shell=True)
    json_str_tests = json_str_tests.decode('cp932')
    json_obj_tests = json.loads(json_str_tests)
    test_count = 0

    for test in json_obj_tests['tests']:
        list_artifacts(test,test_count)
        test_count = test_count + 1
        
    os.chdir("..")
       
def list_artifacts(test,test_count):
    test_arn = test['arn']
    test_name = test['name']
    print("        test_name={0} {1}".format(result2str(test['result']), test_name))
    foldername = "{0:0>5}_{1}_{2}".format(test_count,result2str(test['result']),test_name)
    os.mkdir(foldername)
    os.chdir(foldername)

    list_artifacts_cmd = ('aws devicefarm list-artifacts'
                ' --arn "{0}"' )

    if region != '':
        list_artifacts_cmd += ' --region "{0}"'.format(region)
        
    list_artifacts_cmd = list_artifacts_cmd.format(test_arn)
    
    list_artifacts_(list_artifacts_cmd,"SCREENSHOT")
    list_artifacts_(list_artifacts_cmd,"LOG")
    list_artifacts_(list_artifacts_cmd,"FILE")
    os.chdir("..")

def list_artifacts_(list_artifacts_cmd,type):
    list_artifacts_cmd += ' --type "{0}"'.format(type)

    json_str_artifacts = subprocess.check_output(list_artifacts_cmd, shell=True)
    json_str_artifacts = json_str_artifacts.decode('cp932')
    json_obj_artifacts = json.loads(json_str_artifacts)
    artifact_count = 0

    for artifact in json_obj_artifacts['artifacts']:
        artifact_arn = artifact['arn']
        artifact_name = artifact['name']
        artifact_extension = artifact['extension']
        artifact_url = artifact['url']
        artifact_filename = "{0}.{1}".format(artifact_name,artifact_extension)
        print("          artifact_filename=" + artifact_filename)
        download_file(artifact_filename, artifact_url)

    
def download_file(artifact_filename, artifact_url):
    get_artifacts_cmd = ('curl -s -S -o "{0}" "{1}"' )
    
    get_artifacts_cmd = get_artifacts_cmd.format(artifact_filename,artifact_url)
    result = subprocess.check_output(get_artifacts_cmd, shell=True)
    

def main():
    if devicefarm_run_arn != '':
        list_jobs(devicefarm_run_arn,0)
    else:
        list_runs(devicefarm_project_arn)
                   
if __name__ == '__main__':
  main()
```


#AWS Device Framについて
1. AWS Device Farm、便利ですが、少々お高いのが難点。
2. 安定したテストスクリプトを書くのは難しい
3. テスト中、意図せずネットワークが切れてることがある気がする
4. スクリーンショットは/sdcard/test-screenshots/に保存すれば、Device Farmがテストケース、メソッドまでは整理してくれる