Remote TestKit과 Thrift API

Remote TestKit Thrift API란?

Jenkins등의 CI(Continueous Integration)소프트웨어와의 연계 요구에 대응하기 위하여 실제단말기에 자동테스트를 할 수 있는「Remote TestKit」의Thrift API를 제공하고 있습니다. 대응언어는 Java, PHP, Ruby, Perl 등 입니다. 이전의 Remote TestKit에서는 실제기기를 대여할 때, 사용자가 클라이언트 경유로 수동으로 조작하여 대여하는 방법 밖에 없었기 때문에, Jenkin 등의CI와 연계시킬 경우 사전에 수동으로 단말을 빌려둘 필요가 있었습니다. Remote TestKit Thrift API가 제공됨에 따라 임의의 프로그램에서 Remote TestKit의 각종기능을 사용할 수 있게 되었습니다. 때문에 지금까지는 수동으로 조작해오던 scene을 전부 자동으로 할 수 있게 되었습니다.
<API이용케이스> (이용예1) 코드가 commit 될 때마다 실제기기를 대여하여 가상 adb 경유로 자동테스트를 실행하여 결과를 얻고, 그 과정을 화면 API로 동영상화하여 추후에 참조할 수 있는 시스템 구축 (이용예2) 새로운 기종이 출시될 때마다 자사 사이트의 web사이트를 캡처하여 동영상파일화하고 운용팀에 자동으로 메일로 연락하도록 하는 시스템의 구축

Remote TestKit Thrift API의 구조

Remote TestKit Thrift API는 Apache Thrift의 구조를 이용한 형태로 제공되고 있습니다 Thrift는 원래Facebook사가 여러 가지 언어로 쓰여진 서버 간의 연계를 위해 개발한 것으로, 이후에는Apache에 기증되어 현재도 개발 중입니다. 현재 Evernote API와 Hadoop 등이Thrift를 이용하여 연계하는 프로그램을 개발할 수 있게 되었습니다. http://en.wikipedia.org/wiki/Apache_Thrift Apache Thrift는 API정의로써 thrift 파일을 작성하는 것만으로 다수의 프로그램 언어를 위한 라이브러리를 자동 생성해 주는 tool 입니다. 또한, 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
  • 화면캡처/ 동영상녹화APIAPI

간단한 프로그램에 의한 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프로젝트 루트에 저장한 후, 하기의 command를 실행해 Java용 라이브러리 소스코드를 생성합니다. command: thrift-0.9.1.exe -out srcmainjava --gen java RemoteTestKitAPI.thrift

샘플연계프로그램 작성

실제로 단말을 대여하여, Google의 모바일 사이트를 캡처하는 프로그램을 입력합니다. 하기의 소스코드는 /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 = "<ID>";
        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의 경우: command roadmap 를 실행시켜여 ”<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 class를 실행시켜 주세요. 실행하여 실제로 대여가 시작되면 티켓이 소모되므로 주의 하시기 바랍니다.

샘플연계 프로그램해설

Thrift서버는 메인 서비스와 디바이스 서비스에 관련된 기능을 제공합니다. 메인 서비스는 Device List 등에 관련된 기능을 제공하고 있습니다.
  • 로그인・로그아웃기능
  • Device List・각 단말의 상세정보취득기능
  • 자동대여의 설정변경기능
디바이스 서비스에서는 단말에 관계하는 하기의 기능을 제공하고 있습니다.
  • 단말대여기능
  • 단말상태취득기능
  • 앱설치기능
  • 화면캡처기능
  • 화면녹화기능
  • Web페이지 캡처기능
  • WiFi ON・OFF기능
  • 화면회전기능
  • 가상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));
ID・패스워드를 입력해 로그인합니다.
        System.out.println("Login");
        mainServiceClient.login(USER_NAME, PASSWORD);
로그인이 완료되면 Device List를 얻을 수 있습니다. Device List는 비동기화로 갱신되기 때문에 타이밍에 따라서는 단말이 없는 경우도 발생합니다. 때문에 여기서는 Device List에 단말기가 0인 경우에는 잠시 기다렸다가 다시 취득하는 코드로 되어있습니다.
        while (true) {
            System.out.println("Get device list");
            List<Device> devices = mainServiceClient.getDevices();
            if (devices.isEmpty()) {
                Thread.sleep(1000);
                continue;
            }
Device List에 단말기가 하나라도 표시되어 있다면 선두단말에 대해 취득합니다.
            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 connection 경유로 단말ID를 입력하고 open method를 불러오면 단말대여가 시작됩니다. 대여와 동시에 Thrift connection은 지정한 단말과 연결된 Thrfit connection이 됩니다.
            System.out.println("Rent a device");
            DeviceService.Client deviceServiceClient = new DeviceService.Client(new TBinaryProtocol(deviceServiceTransport));
            deviceServiceClient.open(device.getDeviceId());
URL을 지정하여 We페이지캡처를 하고 프로그램을 종료합니다.
            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 method를 명시적으로 하고 있지 않지만, Thrift서버는 Thrift connection이 끊기면 자동적으로 리소스를 해방합니다. 단말이 close되는 동안, PC버전 클라이언트는 단말상태가 ‘사용중’으로 표시됩니다. close하면 대여시간이 종료되기까지 ‘사용가능’ 상태가 되고 다른 프로그램 등에서 다시 open method를 불러올 수 있게 됩니다. Thrift서버는 open한 후 close하지 않으면 대여가 자동연장되므로 주의바랍니다. 자동연장은 기본적으로는 세시간이지만, 메인서비스의 setMaxRentalMinutes method로 최대자동연장시간을 지정할 수 있습니다. 이 샘플에서는 Web페이지 캡처만 하고 있지만, 녹화 및 가상 adb 등 디바이스 서비스에서는 여러 기능이 준비되어 있으므로 용도에 맞게 사용해주세요.