/**
* personium.io
* Copyright 2014 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
package com.fujitsu.dc.jersey.engine.test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.json.simple.JSONObject;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import com.fujitsu.dc.client.Accessor;
import com.fujitsu.dc.client.Box;
import com.fujitsu.dc.client.Cell;
import com.fujitsu.dc.client.DaoException;
import com.fujitsu.dc.client.DcContext;
import com.fujitsu.dc.client.ServiceCollection;
import com.fujitsu.dc.client.http.DcRequestBuilder;
import com.fujitsu.dc.client.http.DcResponse;
import com.fujitsu.dc.client.http.HttpClientFactory;
import com.fujitsu.dc.engine.utils.DcEngineConfig;
import com.sun.jersey.test.framework.AppDescriptor;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
* engineスクリプトのテストを実行するための基底クラス.
*/
public abstract class ScriptTestBase extends JerseyTest {
/** ローカルテスト用EngineリクエストUrl. */
public static final String LOCAL_TEST_SERVICE_URL = "http://localhost:9998";
/** デフォルトのリクエスト送信先URL. */
public static final String DEFAULT_TARGET_URL = "http://localhost:8080/dc1-core";
/** リクエスト送信先URLを取得するプロパティのキー. */
public static final String PROP_TARGET_URL = "io.personium.test.target";
/** システムプロパティから接続先のURLを取得する。 指定がない場合はデフォルトのURLを使用する. */
static String baseUrl = System.getProperty(PROP_TARGET_URL, DEFAULT_TARGET_URL);
/** サービステスト実施フラグ. */
public static final String PROP_SERVICE_CALL_TEST_FLAG = "io.personium.test.service";
/** システムプロパティからサービステストの実施フラグを取得する。 指定がない場合はFalseを使用する. */
static boolean isServiceTest = Boolean.parseBoolean(System.getProperty(PROP_SERVICE_CALL_TEST_FLAG, "false"));
/** マスタートークン無し運用時、最初のCellは、ユニットユーザー管理Cellにて発行したトークンを利用. */
public static final String PROP_UNITUSER_CELL = "io.personium.test.unituser.cell";
/** システムプロパティからユニットユーザーCell(URL)を取得する。 指定がない場合は未指定を意味する空文字をセットする. */
private static String unitUserCell = System.getProperty(PROP_UNITUSER_CELL, "");
/** ユニットユーザー管理Cellのアカウント. */
public static final String PROP_UNITUSER_CELL_ACCOUNT = "io.personium.test.unituser.account";
/** システムプロパティからユニットユーザーCell(URL)を取得する。 指定がない場合は未指定を意味する空文字をセットする. */
private static String unitUserAccount = System.getProperty(PROP_UNITUSER_CELL_ACCOUNT, "");
/** ユニットユーザー管理Cellのパスワード. */
public static final String PROP_UNITUSER_CELL_PASSWORD = "io.personium.test.unituser.password";
/** システムプロパティからユニットユーザーCell(URL)を取得する。 指定がない場合は未指定を意味する空文字をセットする. */
private static String unitUserPassword = System.getProperty(PROP_UNITUSER_CELL_PASSWORD, "");
/** 基底URLが格納されているヘッダ名. */
protected static final String KEY_HEADER_BASEURL = "X-Baseurl";
/** 共通で作成されたCellオブジェクトの個数. */
private static final int CELL_COUNT = 3;
/** 共通で作成されたCellオブジェクト. */
private static Cell[] testCells = new Cell[CELL_COUNT];
/** 共通で作成されたBoxオブジェクト. */
private static Box[] testBoxs = new Box[CELL_COUNT];
/** 共通で作成されたServiceCollectionオブジェクト. */
static ServiceCollection testSvcCol;
/** テストで利用するAccessor. */
private static Accessor testAs = null;
/** Cell名. */
static String cellName = "enginetest";
/** Box. */
static String boxName = "boxname";
/** Box. */
private static String boxSchema = "box";
/** Account. */
private static String accountName = "user001";
/** サービスサブジェクトアカウント. */
private static String engineAccountName = "engine";
/** Account password. */
private static String accountPassword = "pass001";
/** ServiceCollection名. */
private static String serviceCollectionName = "svccol";
/** サービス名. */
private static String serviceName = "test";
/** サービスパス名. */
private static String serviceScriptPath = "test.js";
/** Httpクライアント. */
HttpClient httpClient = HttpClientFactory.create("insecure", 0);
/** マスタートークン. */
private static String masterToken = DcEngineConfig.getMasterToken();
/** トークン. */
static String token = "";
/** DCコンテキスト. */
private static DcContext dc;
/**
* コンストラクタ.
*/
public ScriptTestBase() {
super();
}
/**
* コンストラクタ.
* @param testContainerFactory .
*/
public ScriptTestBase(TestContainerFactory testContainerFactory) {
super(testContainerFactory);
}
/**
* コンストラクタ.
* @param ad .
*/
public ScriptTestBase(AppDescriptor ad) {
super(ad);
}
/**
* コンストラクタ.
* @param packages .
*/
public ScriptTestBase(String... packages) {
super(packages);
}
/**
* 最初に実行される処理.
* @throws DaoException DAO例外
*/
@BeforeClass
public static final void beforeClass() throws DaoException {
// DAOインスタンスを生成
dc = new DcContext(baseUrl, cellName, boxSchema, boxSchema);
String version = getVersion();
if (version != null && !(version.equals(""))) {
dc.setDcVersion(version);
}
// 利用するトークンを特定
if ("".equals(unitUserCell) || "".equals(unitUserAccount) || "".equals(unitUserPassword)) {
// ユニットユーザーとして認証する情報がなければマスタートークンを利用する
token = masterToken;
dc.setDefaultHeader("X-Dc-Unit-User", "https://example.com/test#UnitUser");
} else {
// ユニットユーザーが指定されていれば、ユニットユーザーで認証したトークンを利用する
Accessor as = dc.asAccount(unitUserCell, unitUserAccount, unitUserPassword);
token = as.cell(baseUrl).getAccessToken();
}
// CLIENTトークンとして、上で取得したトークンをセットする
dc.setClientToken(token);
// テストで利用するAccessorを取得
testAs = dc.withToken(token);
// 前回のテストでリソースが残っている可能性があるので、まずは削除処理を行う
destroyResources();
// テストで利用するリソースを生成する
makeResources();
}
/**
* 最後に実行される処理.
*/
@AfterClass
public static final void afterClass() {
destroyResources();
}
/**
* テスト用に利用するリソースを生成する.
*/
@SuppressWarnings("unchecked")
static void makeResources() {
// Account作成のJSON
JSONObject accountJson = new JSONObject();
accountJson.put("Name", accountName);
// 昇格用アカウント作成のJSON
JSONObject engineAccountJson = new JSONObject();
engineAccountJson.put("Name", engineAccountName);
// Box作成のJSON
JSONObject boxJson = new JSONObject();
boxJson.remove("Name");
boxJson.put("Name", boxName);
// Cell作成のJSON
JSONObject json = new JSONObject();
json.put("Name", cellName);
for (int i = 0; i < testCells.length; i++) {
try {
testCells[i] = testAs.asCellOwner().unit.cell.create(json);
} catch (DaoException e) {
// CONFLICT(409)の場合は、すでにあるCellを利用する
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_CONFLICT) {
fail(e.getMessage());
}
}
// Accountを作成
try {
testCells[i].account.create(accountJson, accountPassword);
// サービスサブジェクトアカウントの作成
testCells[i].account.create(engineAccountJson, null);
} catch (DaoException e) {
// CONFLICT(409)の場合は、すでにあるCellを利用する
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_CONFLICT) {
fail(e.getMessage());
}
}
// Boxを作成
try {
testBoxs[i] = testCells[i].box.create(boxJson);
} catch (DaoException e) {
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_CONFLICT) {
fail(e.getMessage());
}
}
json.remove("Name");
json.put("Name", cellName + (i + 1));
}
try {
if (isServiceTest) {
// サービスコレクションの作成 serviceCollectionName
testBoxs[0].mkService(serviceCollectionName);
testSvcCol = testBoxs[0].service(serviceCollectionName);
// サービスの登録 (PROPPATCH)
testSvcCol.configure(serviceName, serviceScriptPath, engineAccountName);
// スクリプトの登録 (Davのput)
putScript("testCommon.js", "testCommon.js");
}
} catch (DaoException e) {
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_CONFLICT) {
fail(e.getMessage());
}
}
}
/**
* テスト用リソースの削除.
*/
static void destroyResources() {
String name = cellName;
for (int i = 0; i < testCells.length; i++) {
removeCell(name);
name = cellName + (i + 1);
}
}
/**
* CellおよびCell配下のリソースを削除する.
* @param name 対象のCell名
*/
static void removeCell(String name) {
Cell cell = null;
Box box = null;
ServiceCollection svc = null;
try {
if (!testAs.asCellOwner().unit.cell.exists(name)) {
return;
}
cell = testAs.cell(name);
box = cell.box(boxName);
svc = cell.box(boxName).service(serviceCollectionName);
} catch (DaoException e) {
fail(e.getMessage());
}
try {
if (isServiceTest) {
// スクリプトの削除 (Davのdelete)
svc.del("testCommon.js");
// サービスコレクションの削除
box.del(serviceCollectionName);
}
} catch (DaoException e) {
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_NOT_FOUND) {
fail(e.getMessage());
}
}
// Box削除
try {
cell.box.del(boxName);
} catch (DaoException e) {
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_NOT_FOUND) {
fail(e.getMessage());
}
}
// Account削除
try {
cell.account.del(accountName);
// サービスサブジェクトアカウントの削除
cell.account.del(engineAccountName);
} catch (DaoException e) {
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_NOT_FOUND) {
fail(e.getMessage());
}
}
// Cell削除
try {
testAs.asCellOwner().unit.cell.del(name);
} catch (DaoException e) {
if (Integer.parseInt(e.getCode()) != HttpStatus.SC_NOT_FOUND) {
fail(e.getMessage());
}
}
}
/**
* 異常なレスポンスのテストパターン.
*/
protected static class IllegalResponseFixture {
String responseMessage;
String requestJson;
IllegalResponseFixture(String responseMessage, String requestJson) {
this.responseMessage = responseMessage;
this.requestJson = requestJson;
}
}
/**
* スクリプトの登録.
* @param resourceName リソース名
* @param fileName ファイル名
*/
protected static void putScript(final String resourceName, final String fileName) {
// スクリプトの登録 (Davのput)
String testFilename = ScriptTest.class.getResource("/service/" + resourceName).getFile();
// DAVファイル登録
// dc.setChunked(false);
try {
FileInputStream fis = new FileInputStream(testFilename);
testSvcCol.put(fileName, "text/plain", fis, "*");
} catch (DaoException e) {
fail(e.getMessage());
} catch (FileNotFoundException e) {
fail(e.getMessage());
}
}
/**
* サービスを実行.
* @param name サービス名
*/
protected void callService(final String name) {
String url;
if (isServiceTest) {
// スクリプトの登録 (Davのput)
putScript(name, "test.js");
url = requestUrl();
} else {
url = requestUrl(name);
}
// サービスの実行
callServiceTest(url);
if (isServiceTest) {
// スクリプトの削除(Davのdel)
try {
testSvcCol.del("test.js");
} catch (DaoException e) {
fail(e.getMessage());
}
}
}
/**
* テスト実施.
* @param url 実施スクリプトurl
*/
private void callServiceTest(final String url) {
try {
HttpUriRequest req = new DcRequestBuilder().url(url).method("GET").token(token).build();
req.setHeader(KEY_HEADER_BASEURL, baseUrl);
String version = getVersion();
if (version != null && !(version.equals(""))) {
req.setHeader("X-Dc-Version", version);
}
DcResponse res = request(req);
assertEquals(HttpStatus.SC_OK, res.getStatusCode());
assertEquals("OK", res.bodyAsString());
} catch (DaoException e) {
fail(e.getMessage());
}
}
/**
* テスト用のリクエストURL文字列を組み立てる.
* @return 生成したURL文字列
*/
protected String requestUrl() {
return String.format("%s/%s/%s/%s/test?cell=%s", baseUrl, cellName, boxName, serviceCollectionName, cellName);
}
/**
* テスト用のリクエストURL文字列を組み立てる.
* @param name 実行するスクリプト名
* @return 生成したURL文字列
*/
protected String requestUrl(final String name) {
return String.format("%s/%s/%s/test/%s?cell=%s", LOCAL_TEST_SERVICE_URL, cellName, boxName, name, cellName);
}
/**
* Reponseボディを受ける場合のHTTPリクエストを行う.
* @param httpReq HTTPリクエスト
* @return DCレスポンスオブジェクト
* @throws DaoException DAO例外
*/
protected DcResponse request(final HttpUriRequest httpReq) throws DaoException {
try {
HttpResponse objResponse = httpClient.execute(httpReq);
DcResponse dcRes = new DcResponse(objResponse);
int statusCode = objResponse.getStatusLine().getStatusCode();
if (statusCode >= HttpStatus.SC_MULTIPLE_CHOICES) {
throw DaoException.create("{\"io exception\" : " + dcRes.bodyAsString() + "}", statusCode);
}
return dcRes;
} catch (IOException ioe) {
throw DaoException.create("{\"io exception\" : " + ioe.getMessage() + "}", 0);
}
}
/**
* テスト対象のバージョンを取得する.
* @return テスト対象のバージョン
*/
protected static String getVersion() {
return DcEngineTestConfig.getVersion();
}
}