Remote TestKit Thrift API

Remote TestKit Thrift APIとは

JenkinsなどのCI(継続的インテグレーション)ソフトウェアとの連携のご要望にお答えして、実端末に対して自動テストを実行することが可能な「Remote TestKit」のThrift APIの提供をしております。対応言語はJava、PHP、Ruby、Perl となります。 以前のRemote TestKitでは、実機をレンタルする場合、ユーザがクライアントソフト経由で手動で操作して借りるしか方法がありませんでした。そのため、Jenkin等のCIと連携させたりする際には、事前に手動で端末を借りておく必要がありました。 Remote TestKit Thrift APIが提供されたことにより、任意のプログラムがRemote TestKitの各種機能を使うことができるようになりました。そのため、今まで手動で操作していたシーンを全自動で行うことが可能になります。 <API利用ケース> (利用例1) コードがコミットされるたびに実機をレンタルして、仮想adb経由で自動テストを走らせて結果を取得し、その遷移を録画APIでムービーファイル化して参照できるようなシステムの構築。 (利用例2) 新しい機種がリリースされるたびに、自社サイトのWebページをキャプチャして画像ファイル化し、運用チームに自動でメールするようなシステムの構築。

Remote TestKit Thrift APIの仕組み

Remote TestKit Thrift APIは、Apache Thriftの仕組みを用いる形で提供されています。 Thriftは元々Facebook社が様々な言語で書かれたサーバ間を連携させるために開発したもので、後にApacheに寄贈されて現在も開発が続いています。現在Evernote APIやHadoop等がThriftを用いて連携するプログラムを開発できるようにしています。 http://ja.wikipedia.org/wiki/Apache_Thrift Apache Thriftは、API定義としてthriftファイルを作成するだけで、多数のプログラム言語向けのライブラリを自動生成してくれるツールです。さらに、Thriftの定義は、構造体・列挙型・例外等をサポートしており、静的な型をベースとした使いやすいライブラリを生成してくれます。 Remote TestKitにてThriftを用いて、連携プログラムを作成するには、下記のような手順を踏む必要があります。

Remote TestKit Thrift APIの利用の流れ

Remote TestKit Thrift APIは、各言語ごとのライブラリ(dllファイル・jarファイル等)ではなく、thriftファイルとして提供されますので、Thriftでサポートされている任意の言語で利用することができます。 ※thriftファイルの利用を希望される方はお問合せまで連絡ください 利用にあたっては、下記の手順で使いたいプログラム言語向けのライブラリを生成した後に、Thrift APIサーバを立ち上げて連携プログラムを実行する必要があります。
  1. "RemoteTestKitAPI.thrift(Remote TestKit Thrift APIの定義ファイル)"をthriftコンパイラでコンパイルして定義から任意の言語向けのライブラリを生成
  2. Thriftの実行時に必要となる依存ライブラリをダウンロード
  3. Remote TestKit Thrift APIを用いたプログラムを作成
  4. Remote TestKit Thrfit APIサーバをローカルPCで起動
  5. 開発した連携プログラムを実行

提供するThrift API一例

  • 端末のレンタル・自動延長API
  • WebページキャプチャAPI
  • 仮想adb有効化API
  • 画面キャプチャ・動画録画API

簡単なプログラムによるAPI利用例

はじめに

このチュートリアルでは、Remote TestKit Thrift APIを用いて、端末をレンタルしてWebページをキャプチャするプログラムを作成します。 下記の構成を前提としたチュートリアルとなっていますので、環境に合わせて適宜読み替えてください。
  • OS: Windows 7
  • Java実行環境: Java 7
  • ビルド環境: Maven

空のMavenプロジェクトを作成

Thriftで生成されたライブラリを用いるには、Thriftが依存するライブラリが必要となります。各ライブラリをそれぞれのサイトから手動でダウンロードすることも可能ですが、手間がかかるため、このチュートリアルではMavenプロジェクトを作成して、依存ライブラリをpom.xmlに設定して自動でダウンロードさせます。 下記のMavenプロジェクトを作成してください。
  • groupdId: nttr.rtk.example
  • artifactId: rtk-example
  • version: 任意
その後、作成したMavenプロジェクトのpom.xmlにlibthriftを追加して依存ライブラリを設定してください。Java 7でコンパイル・実行しますので、pom.xmlではJava 7でビルドさせるようにmaven-compiler-pluginも設定します。最終的に、pom.xmlは下記のようになります。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>nttr.rtk.example</groupId>
    <artifactId>rtk-example</artifactId>
    <version>1.0</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.9.1</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

RemoteTestKitAPI.thriftからJava向けライブラリを生成

Apache Thriftのページより、thriftファイルからライブラリのソースコードを生成するthriftコンパイラ(thrift-0.9.1.exe)をダウンロードして、先ほど作成したMavenプロジェクトのルートに保存します。 http://thrift.apache.org/download その後、Remote TestKit Thrift APIのthriftファイル(RemoteTestKitAPI.thrift)を、Mavenプロジェクトのルートに保存した後に下記のコマンドを実行してJava用ライブラリのソースコードを生成します。 コマンド: thrift-0.9.1.exe -out src/main/java --gen java RemoteTestKitAPI.thrift

サンプルの連携プログラムを作成

実際に端末をレンタルして、Googleのモバイルサイトをキャプチャするプログラムを入力します。 下記のソースコードを、<Mavenプロジェクトのルートディレクトリ>/src/main/java/example/Main.javaとして保存してください。保存する前に、USER_NAMEとPASSWORDは自分のアカウント情報に変更してください。
package example;

import java.io.File;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFileChooser;

import nttr.rtk.thrift.Device;
import nttr.rtk.thrift.DeviceService;
import nttr.rtk.thrift.MainService;
import nttr.rtk.thrift.ServicePorts;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;

public class Main {
    public static void main(String[] args) throws Exception {
        String USER_NAME = "<ユーザ名>";
        String PASSWORD = "<パスワード>";

        System.out.println("Connect to main service");
        TSocket mainServiceTransport = new TSocket("localhost", ServicePorts.MAIN_SERVICE_PORT.getValue());
        mainServiceTransport.open();
        MainService.Client mainServiceClient = new MainService.Client(new TBinaryProtocol(mainServiceTransport));

        System.out.println("Login");
        mainServiceClient.login(USER_NAME, PASSWORD);

        while (true) {
            System.out.println("Get device list");
            List<Device> devices = mainServiceClient.getDevices();
            if (devices.isEmpty()) {
                Thread.sleep(1000);
                continue;
            }

            Device device = devices.get(0);

            System.out.println("Connect to device service");
            TSocket deviceServiceTransport = new TSocket("localhost", ServicePorts.DEVICE_SERVICE_PORT.getValue());
            deviceServiceTransport.open();

            System.out.println("Rent a device");
            DeviceService.Client deviceServiceClient = new DeviceService.Client(new TBinaryProtocol(deviceServiceTransport));
            deviceServiceClient.open(device.getDeviceId());

            System.out.println("Capturing web pages");
            String myDocumentDirectoryPath = new JFileChooser().getFileSystemView().getDefaultDirectory().toString();
            deviceServiceClient.captureWebPages(Arrays.asList("http://www.google.co.jp"), new File(myDocumentDirectoryPath,
            "tmp").getAbsolutePath());
            break;
        }
    }
}

Remote TestKit Thrift APIサーバを起動

Remote TestKit Thrift APIを使う際には、Remote TestKitサーバとの間に中継サーバ(以下Thriftサーバ)を立ち上げる必要があります。Remote TestKit Thrift APIを使う連携プログラムは、Thriftサーバ経由で各種やりとりをRemote TestKitサーバと行う形となっています。 Remote TestKit Thrift APIは、中継サーバを使う方式で実現されていることによって、下記のメリットがあります。
  • 録画APIなどファイルを生成するAPIを使う際に、結果ファイルをサーバからダウンロードするのではなく、直接ローカルのファイルシステムに書き出す形となるので待ち時間やネットワーク負荷が少なくなる
  • Thriftでサポートされているプログラム言語の多くでSSLによる通信の暗号化を行えませんが、中継サーバがRemote TestKitサーバとの通信を暗号化することにより、安全にRemote TestKitサーバとやりとりを行うことができる http://wiki.apache.org/thrift/LibraryFeatures?action=show&redirect=LanguageSupport
  • 仮想adb機能のような特殊な機能が利用できる
Thriftサーバですが、WindowsとOS Xで起動方法が異なります。 Windowsの場合: コマンドプロンプトを起動して、"<Remote TestKitをインストールしたディレクトリ>ThriftApiServer.exe(x64版Windows 7の場合には、c:Program Files (x86)Remote TestKitThriftApiServer.exe)"と入力して実行 OS Xの場合: ターミナルを起動して以下のように入力して実行してください。
 $ cd "/Applications/Remote TestKit.app/Contents/MacOS" ; java -cp "../Java/*" -Dconf.directory.company.name=nttr nttr.rtk.MainForThriftServer

サンプルの連携プログラムを実行

先ほど作成したMainクラスを実行してください。実行すると実際にレンタルが行われ、チケットが消費されるのでご注意ください。

サンプルの連携プログラムの解説

Thriftサーバは、二つのポートで待ち受けており、それぞれのポートがメインサービスとデバイスサービスの受け口となっています。 メインサービスは、端末一覧等の全般に関係する機能を提供しています。
  • ログイン・ログアウト機能
  • 端末一覧・各端末ごとの詳細情報の取得機能
  • 自動レンタルの設定変更機能
デバイスサービスは、端末に関係する下記機能を提供しています。
  • 端末レンタル機能
  • 端末の状態取得機能
  • アプリのインストール機能
  • 画面キャプチャ機能
  • 画面録画機能
  • Webページキャプチャ機能
  • WiFiオン・オフ機能
  • 画面回転機能
  • 仮想adb機能
  • ロケール設定機能
メインサービスとデバイスサービスは別々のポートで待ち受けていますが、各ポートへのThriftコネクションは一つのコンテキストを共有しています。 ですので、メインサービス経由でログインした後に、デバイスサービスを使うという形となっています。 そのため、Thriftサーバの一プロセスでログインできるのは、一アカウントのみとなりますのでご注意ください。 それでは、上記を踏まえて先ほどのサンプルの連携プログラムを見ていきます。 まずは、ローカルに立ち上げたThriftサーバのメインサービスのポートに接続を行います。
        TSocket mainServiceTransport = new TSocket("localhost", ServicePorts.MAIN_SERVICE_PORT.getValue());
        mainServiceTransport.open();
その後、ThriftのBinaryプロトコルで接続して、thriftコンパイラ経由で生成したクラスを使ってクライアントインスタンスを作成します。 (Thriftはサーバ・クライアント間のやりとりで複数のプロトコルをサポートしていますが、Thriftサーバでは最も一般的なBinaryプロトコルでしか接続できません。)
        MainService.Client mainServiceClient = new MainService.Client(new TBinaryProtocol(mainServiceTransport));
ユーザ名・パスワードを指定してログインします。
        System.out.println("Login");
        mainServiceClient.login(USER_NAME, PASSWORD);
ログインが完了すると端末リストが取得できるようになります。 端末リストですが、非同期で更新されるため、タイミングによってはまったく端末がない状態があり得ます。 そのため、ここでは端末リストが空だった場合には、一秒間待ってから再度取得するコードとなっています。
        while (true) {
            System.out.println("Get device list");
            List<Device> devices = mainServiceClient.getDevices();
            if (devices.isEmpty()) {
                Thread.sleep(1000);
                continue;
            }
端末リストが空でなかった場合には先頭の端末を取得します。
            Device device = devices.get(0);
先頭の端末をレンタルするために、デバイスサービスに接続します。
            System.out.println("Connect to device service");
            TSocket deviceServiceTransport = new TSocket("localhost", ServicePorts.DEVICE_SERVICE_PORT.getValue());
            deviceServiceTransport.open();
デバイスサービスに接続したThriftコネクション経由で、端末IDを指定してopenメソッドを呼び出すことで、端末のレンタルが行われます。 レンタルと同時に、このThriftコネクションは、指定した端末と紐づいたThrfitコネクションとなります。
            System.out.println("Rent a device");
            DeviceService.Client deviceServiceClient = new DeviceService.Client(new TBinaryProtocol(deviceServiceTransport));
            deviceServiceClient.open(device.getDeviceId());
URLを指定してWebページのキャプチャを行ってプログラムを終了します。
            System.out.println("Capturing web pages");
            String myDocumentDirectoryPath = new JFileChooser().getFileSystemView().getDefaultDirectory().toString();
            deviceServiceClient.captureWebPages(Arrays.asList("http://www.google.co.jp"), new File(myDocumentDirectoryPath,
             "tmp").getAbsolutePath());
            break;
サンプルの連携プログラムではcloseメソッドを明示的に行っていませんが、ThriftサーバはThriftコネクションが切れると自動的にリソースを解放します。 端末は、open→closeの間は、PC版クライアントの"起動中"状態となります。 closeを行うとレンタル時間が終了するまでは、"起動可能"状態となり、別プログラム等から再度openメソッドを呼び出すことが可能となります。 Thriftサーバにおいては、openした後にcloseしなければ、レンタルが自動延長されますのでご注意ください。 自動延長はデフォルトでは三時間行われますが、メインサービスのsetMaxRentalMinutesメソッドで最大自動延長時間を指定することが可能です。 このサンプルではWebページのキャプチャしか行っていませんが、録画や仮想adb等、デバイスサービスには様々な機能が用意されていますので用途に応じてお使いください。