在非GAE环境尝试使用VTS Dashboard

虽然VTS Dashboard是专为GAE而开发的,但是仍然有办法在非GAE环境下进行开发与运行。 本文介绍如何在普通的Linux环境下运行一个VTS Dashboard,并且进行数据上传。 这只是一次评估性质的尝试,结果以失败而告终。

test/vts库简介

这个Git库是一个复合库,包含了Java、C++、Python等代码,主要有三种内容。

  1. 编译出vts-tradefed,主要是Java,包含C++。
  2. vts的runner,在vts-tradefed中通过run vts的执行逻辑,主要是Python。
  3. web/dashboard/目录下的GAE项目,即本文关注的VTS Dashboard网站。

主要有两类分支。 一是像master这样的开发分支,里面没有web这个目录,更不用说web/dashboard/目录了。 二是像oreo-release这样的分支,里面有web/dashboard/。 所以,取用VTS Dashboard时,需要切换到第二类分支。

根据Git库中的README进行配置,就是一个大坑,因为这些描述都太陈旧了。 codelabs/android-vts#10上的说明,才可以作为有效参考。

由于国内访问android.googlesource.com有一个总所周知的问题,孤特地在Gitee建立了一个镜像库yanqd0/vts

运行VTS Dashboard

在任何一个安装了JDK 8(以上)与Maven的环境中,下载AOSP的一个Git库test/vts/,即可运行一个VTS Dashboard。

git clone https://android.googlesource.com/platform/test/vts/ -b oreo-release
# or
# git clone https://gitee.com/yanqd0/vts.git -b oreo-release
cd vts/web/dashboard
mvn appengine:devserver

官方文档中说,还需要安装GAE的SDK。 然而,如果不需要部署到GAE环境,这是没有必要的,Maven会安装运行需要的jar。

如果需要跑在后台,在执行完mvn appengine:devserver编译后, 可以用mvn appengine:devserver_start来启动,用mvn appengine:devserver_stop来停止。

在8080端口,已经可以访问网页了,只是没有数据。

删除鉴权代码

上传时会用到唯一的一个API——api/datastore,它在web/dashboard/src/main/java/com/android/vts/api/DatastoreRestServlet.java文件。 这里有一段鉴权的代码,需要删除,否则无法成功上传测试数据。

diff --git a/web/dashboard/src/main/java/com/android/vts/api/DatastoreRestServlet.java b/web/dashboard/src/main/java/com/android/vts/api/DatastoreRestServlet.java
index e73f270f..f8e0b775 100644
--- a/web/dashboard/src/main/java/com/android/vts/api/DatastoreRestServlet.java
+++ b/web/dashboard/src/main/java/com/android/vts/api/DatastoreRestServlet.java
@@ -58,25 +58,6 @@ public class DatastoreRestServlet extends HttpServlet {
             return;
         }
 
-        // Verify service account access token.
-        boolean authorized = false;
-        if (postMessage.hasAccessToken()) {
-            String accessToken = postMessage.getAccessToken();
-            GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
-            Oauth2 oauth2 =
-                    new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
-                            .build();
-            Tokeninfo tokenInfo = oauth2.tokeninfo().setAccessToken(accessToken).execute();
-            if (tokenInfo.getIssuedTo().equals(SERVICE_CLIENT_ID)) {
-                authorized = true;
-            }
-        }
-
-        if (!authorized) {
-            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
-            return;
-        }
-
         for (TestReportMessage testReportMessage : postMessage.getTestReportList()) {
             DatastoreHelper.insertData(testReportMessage);
         }

在GAE上正式运行时,当然是不需要这么干的。

上传数据

在一个可以成功执行VTS测试的环境下,只需要修改默认的TestCase配置,即可实现上传。 Git库中的tools/vts-tradefed/res/default/DefaultTestCase.config,这其实是一个JSON文件。 新增或修改以下三个字段:

{
  "enable_web": true,
  "service_key_json_path": "service_key.json",
  "dashboard_post_command": "wget --post-file=\'{path}\' <url>/api/datastore"
}

其中,<url>需要换成VTS Dashboard架设的位置。 如果在本机,可以填http://localhost:8080

service_key.json

service_key.json需要是一个从GAE的设置中获取的鉴权信息文件。

在调试情况下,只能伪造一个。 在编译好的android-vts测试套件中,新增一个空文件即可。

touch testcases/service_key.json

修改鉴权文件解析代码

空的鉴权文件,当然是不能成功执行的。 还需要修改相关的检查代码。

diff --git a/utils/python/web/dashboard_rest_client.py b/utils/python/web/dashboard_rest_client.py
index 8f2be9dc..fbf66b91 100644
--- a/utils/python/web/dashboard_rest_client.py
+++ b/utils/python/web/dashboard_rest_client.py
@@ -46,16 +46,6 @@ class DashboardRestClient(object):
         Returns:
             True if the client is initialized successfully, False otherwise.
         """
-        try:
-            self.auth_token = service_account.ServiceAccountCredentials.from_json_keyfile_name(
-                self.service_json_path, [_OPENID_SCOPE])
-            self.auth_token.get_access_token()
-        except IOError as e:
-            logging.error("Error reading service json keyfile: %s", e)
-            return False
-        except (ValueError, KeyError) as e:
-            logging.error("Invalid service json keyfile: %s", e)
-            return False
         return True
 
 
@@ -69,7 +59,7 @@ class DashboardRestClient(object):
             String, an OAuth2 token using the service account credentials.
             None if authentication fails.
         """
-        return str(self.auth_token.get_access_token().access_token)
+        return 'faked_token'
 
     def PostData(self, post_message):
         """Post data to the dashboard database.

以上diff代码块,以及前面那一段Java的,都可以保存为patch文件,通过git apply打到这个库中。 也可以直接修改编译好的android-vts中的对应内容。

java.lang.StackOverflowError

在Dashboard网站运行一段时间后,会出现以下问题:

HTTP ERROR 500

Problem accessing /. Reason:

    INTERNAL_SERVER_ERROR

Caused by:

java.lang.StackOverflowError
	at java.security.AccessController.doPrivileged(Native Method)
	at java.io.FilePermission.init(FilePermission.java:203)
	...
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
	at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:442)
	at java.lang.SecurityManager.checkRead(SecurityManager.java:888)

Powered by Jetty://

一个超过千行的调用栈,溢出了也属正常。 不过,网站挂了就是挂了,修改JVM参数也调不好。

总结

在摧毁了鉴权相关逻辑以后,数据终于可以上传了。 然而,只在后台可以看到,在网页界面上仍然没有任何内容,也许与鉴权部分有关吧。 此外,网站会因为java.lang.StackOverflowError而挂掉,也是一个无解的问题。

通过VTS测试,可以产生一些数据,包括时间、测试手机设备信息、测试case名称、是否成功、测试覆盖率等信息。 这些信息默认会打包成一个zip文件,放在results目录下。 在有了VTS Dashboard以后,这些数据会被统一上传到网站后台的数据库,并且用漂亮的界面进行展示。 做了相关配置后,run vts过程中会额外插入一个过程,把数据打包成protobuf,进行上传。

然而,VTS Dashboard本质上就是一个GAE项目,无法在非GAE环境下正常使用(孤前面的尝试完全失败了)。 对中国开发者来说,这就是一个不存在的项目。

不过,如果只是集成到CI中,或者展示测试覆盖率,这些功能可以通过既有的手段自行实现,倒是不用依赖Google。 存储、处理大规模的测试数据,这个麻烦一些,但问题也不大。 只需要实现一个api/datastore,即可最小地改动VTS测试套件的代码(即删除或修改准备鉴权json文件的相关处理),收取测试数据。 所以,VTS Dashboard对中国来说,需要一个替代,但也并非必须。


相关笔记