/**
* 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.test.unit.core.model.impl.es.repair;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.MediaType;
import org.apache.http.HttpStatus;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import com.fujitsu.dc.common.ads.AdsWriteFailureLogException;
import com.fujitsu.dc.common.ads.AdsWriteFailureLogInfo;
import com.fujitsu.dc.common.ads.AdsWriteFailureLogWriter;
import com.fujitsu.dc.common.es.EsIndex;
import com.fujitsu.dc.common.es.EsType;
import com.fujitsu.dc.common.es.response.DcSearchHit;
import com.fujitsu.dc.common.es.response.DcSearchResponse;
import com.fujitsu.dc.common.es.util.IndexNameEncoder;
import com.fujitsu.dc.core.DcCoreConfig;
import com.fujitsu.dc.core.DcCoreLog;
import com.fujitsu.dc.core.model.Cell;
import com.fujitsu.dc.core.model.impl.es.EsModel;
import com.fujitsu.dc.core.model.impl.es.ads.Ads;
import com.fujitsu.dc.core.model.impl.es.ads.AdsException;
import com.fujitsu.dc.core.model.impl.es.ads.JdbcAds;
import com.fujitsu.dc.core.model.impl.es.doc.CellDocHandler;
import com.fujitsu.dc.core.model.impl.es.doc.EntitySetDocHandler;
import com.fujitsu.dc.core.model.impl.es.doc.UserDataDocHandler;
import com.fujitsu.dc.core.model.impl.es.odata.UserDataODataProducer;
import com.fujitsu.dc.core.model.lock.Lock;
import com.fujitsu.dc.core.model.lock.LockKeyComposer;
import com.fujitsu.dc.core.webcontainer.listener.RepairServiceLauncher;
import com.fujitsu.dc.test.categories.Unit;
import com.fujitsu.dc.test.jersey.AbstractCase;
import com.fujitsu.dc.test.jersey.DcRunner;
import com.fujitsu.dc.test.utils.BoxUtils;
import com.fujitsu.dc.test.utils.CellUtils;
import com.fujitsu.dc.test.utils.DavResourceUtils;
import com.fujitsu.dc.test.utils.EntityTypeUtils;
import com.fujitsu.dc.test.utils.UserDataUtils;
import com.sun.jersey.test.framework.WebAppDescriptor;
/**
* マスタ自動復旧機能のcoreとの結合テストクラス.
*/
@RunWith(DcRunner.class)
@Category({Unit.class })
public class RepairAdsIntegrationTest extends AbstractCase {
private String cellName = "repairAdsTestCell";
private String owner = "repairadstest";
private Ads ads;
private static final Map<String, String> INIT_PARAMS = new HashMap<String, String>();
static {
INIT_PARAMS.put("com.sun.jersey.config.property.packages",
"com.fujitsu.dc.core.rs");
INIT_PARAMS.put("com.sun.jersey.spi.container.ContainerRequestFilters",
"com.fujitsu.dc.core.jersey.filter.DcCoreContainerFilter");
INIT_PARAMS.put("com.sun.jersey.spi.container.ContainerResponseFilters",
"com.fujitsu.dc.core.jersey.filter.DcCoreContainerFilter");
}
/**
* コンストラクタ.
*/
public RepairAdsIntegrationTest() {
super(new WebAppDescriptor.Builder(INIT_PARAMS).build());
}
/**
* core経由で登録されたCellデータをMySQLに登録できること.
* @throws AdsException MySQL操作失敗
*/
@Before
public void before() throws AdsException {
try {
ads = new JdbcAds();
} catch (AdsException e) {
return;
}
}
/**
* personium経由で登録されたCellデータをMySQLに登録できること.
* @throws AdsException MySQL操作失敗
*/
@Test
public void persnoium経由で登録されたCellデータをMySQLに登録できること() throws AdsException {
String indexName = DcCoreConfig.getEsUnitPrefix() + "_" + IndexNameEncoder.encodeEsIndexName("ad");
String dbName = DcCoreConfig.getEsUnitPrefix() + "_" + IndexNameEncoder.encodeEsIndexName(owner);
// ESアクセス情報
String esTypeName = Cell.EDM_TYPE_NAME;
String routingId = EsIndex.CELL_ROUTING_KEY_NAME;
String searchFieldName = "Name";
String searchFieldValue = cellName;
try {
// personium.io経由でCell登録(UnitUser指定)
CellUtils.create(cellName, MASTER_TOKEN_NAME, owner, HttpStatus.SC_CREATED);
// ESからデータ取得
DcSearchHit esHit = searchFromEs(indexName, esTypeName, routingId, searchFieldName, searchFieldValue);
String id = esHit.getId();
EntitySetDocHandler esDocument = new CellDocHandler(esHit);
// MySQLから該当データ検索(比較用に控えておく)
List<String> idList = new ArrayList<String>();
idList.add(id);
// MySQLにデータが登録されていることを確認
List<JSONObject> adsResponceBefore = ads.searchCellList(dbName, idList);
assertEquals(1, adsResponceBefore.size());
// MySQLから該当データ削除
ads.deleteCell(dbName, id);
// 取得したデータを元にジャーナルログ作成
String lockKey = LockKeyComposer.fullKeyFromCategoryAndKey(Lock.CATEGORY_ODATA,
esDocument.getCellId(), null, null);
AdsWriteFailureLogInfo loginfo = new AdsWriteFailureLogInfo(
esDocument.getUnitUserName(), esDocument.getType(), lockKey,
esDocument.getCellId(), esDocument.getId(),
AdsWriteFailureLogInfo.OperationKind.CREATE, 1, esDocument.getUpdated());
recordAdsWriteFailureLog(loginfo);
// リペア実行
RepairServiceLauncher.RepairAdsService service = new RepairServiceLauncher.RepairAdsService();
service.run();
// データがリペアされていることを確認(データが存在すること)
List<JSONObject> adsResponceAfter = ads.searchCellList(dbName, idList);
// データがリペアされていることを確認(削除前とリペア後のCellが一致すること)
assertEquals(((JSONObject) adsResponceBefore.get(0)).get("id"), ((JSONObject) adsResponceAfter.get(0))
.get("id"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("u"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("u"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("d"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("d"));
assertEquals(
((JSONObject) adsResponceBefore.get(0).get("source")).get("s"),
((JSONObject) adsResponceBefore.get(0).get("source")).get("s"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("b"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("b"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("c"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("c"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("p"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("p"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("a"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("a"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("n"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("n"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("ll"), ((JSONObject) adsResponceAfter
.get(0).get("source")).get("ll"));
assertEquals(
((JSONObject) adsResponceBefore.get(0).get("source")).get("h"),
((JSONObject) adsResponceBefore.get(0).get("source")).get("h"));
assertEquals(
((JSONObject) adsResponceBefore.get(0)).get("type"),
((JSONObject) adsResponceAfter.get(0)).get("type"));
// personium.io経由でCell削除
CellUtils.delete(MASTER_TOKEN_NAME, cellName, HttpStatus.SC_NO_CONTENT);
// データが削除されていること
adsResponceAfter = ads.searchCellList(dbName, idList);
assertEquals(0, adsResponceAfter.size());
} finally {
CellUtils.delete(MASTER_TOKEN_NAME, cellName, -1);
}
}
/**
* core経由で登録されたODATAデータをMySQLに登録できること.
* @throws AdsException MySQL操作失敗
*/
@SuppressWarnings("unchecked")
@Test
public void core経由で登録されたODATAデータをMySQLに登録できること() throws AdsException {
String userDataIndexName = DcCoreConfig.getEsUnitPrefix() + "_" + IndexNameEncoder.encodeEsIndexName(owner);
// ESアクセス情報
String userDataEsTypeName = UserDataODataProducer.USER_ODATA_NAMESPACE;
String userDataSearchFieldName = "__id";
String userDataSearchFieldValue = "userDataId";
String boxName = "testBox";
String colName = "testCol";
String entityType = "testEntityType";
String userDataId = "userDataId";
try {
JSONObject body = new JSONObject();
body.put("__id", userDataId);
// 事前にデータ登録
CellUtils.create(cellName, MASTER_TOKEN_NAME, owner, HttpStatus.SC_CREATED);
BoxUtils.create(cellName, boxName, MASTER_TOKEN_NAME, HttpStatus.SC_CREATED);
DavResourceUtils
.createODataCollection(MASTER_TOKEN_NAME, HttpStatus.SC_CREATED, cellName, boxName, colName);
EntityTypeUtils.create(cellName, MASTER_TOKEN_NAME, boxName, colName, entityType,
HttpStatus.SC_CREATED);
UserDataUtils
.create(MASTER_TOKEN_NAME, HttpStatus.SC_CREATED, body, cellName, boxName, colName, entityType);
// ESからデータ取得
String cellIndexName = DcCoreConfig.getEsUnitPrefix() + "_" + IndexNameEncoder.encodeEsIndexName("ad");
DcSearchHit cellEsHit = searchFromEs(cellIndexName, Cell.EDM_TYPE_NAME, EsIndex.CELL_ROUTING_KEY_NAME,
"Name", cellName);
String cellId = cellEsHit.getId();
DcSearchHit userDataEsHit = searchFromEs(userDataIndexName, userDataEsTypeName, cellId,
userDataSearchFieldName,
userDataSearchFieldValue);
EntitySetDocHandler esDocument = new UserDataDocHandler(userDataEsHit);
// MySQLから該当データ検索(比較用に控えておく)
List<String> idList = new ArrayList<String>();
idList.add(userDataEsHit.getId());
// MySQLにデータが登録されていることを確認
List<JSONObject> adsResponceBefore = ads.searchEntityList(userDataIndexName, idList);
assertEquals(1, adsResponceBefore.size());
// MySQLから該当データ削除
ads.deleteEntity(userDataIndexName, userDataEsHit.getId());
// 取得したデータを元にジャーナルログ作成
String lockKey = LockKeyComposer.fullKeyFromCategoryAndKey(Lock.CATEGORY_ODATA,
esDocument.getCellId(), esDocument.getBoxId(), esDocument.getNodeId());
AdsWriteFailureLogInfo loginfo = new AdsWriteFailureLogInfo(
userDataIndexName, esDocument.getType(), lockKey,
esDocument.getCellId(), esDocument.getId(),
AdsWriteFailureLogInfo.OperationKind.CREATE, 1, esDocument.getUpdated());
recordAdsWriteFailureLog(loginfo);
// リペア実行
RepairServiceLauncher.RepairAdsService service = new RepairServiceLauncher.RepairAdsService();
service.run();
// データがリペアされていることを確(データが存在すること)
List<JSONObject> adsResponceAfter = ads.searchEntityList(userDataIndexName, idList);
assertEquals(((JSONObject) adsResponceBefore.get(0)).get("id"), ((JSONObject) adsResponceAfter.get(0))
.get("id"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("u"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("u"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("d"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("d"));
assertEquals(
((JSONObject) adsResponceBefore.get(0).get("source")).get("s"),
((JSONObject) adsResponceAfter.get(0).get("source")).get("s"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("b"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("b"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("c"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("c"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("p"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("p"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("a"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("a"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("n"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("n"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("ll"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("ll"));
assertEquals(((JSONObject) adsResponceBefore.get(0).get("source")).get("t"), ((JSONObject)
adsResponceAfter
.get(0).get("source")).get("t"));
assertEquals(
((JSONObject) adsResponceBefore.get(0).get("source")).get("h"),
((JSONObject) adsResponceBefore.get(0).get("source")).get("h"));
assertEquals(((JSONObject) adsResponceBefore.get(0)).get("type"),
((JSONObject) adsResponceAfter.get(0)).get("type"));
} finally {
UserDataUtils.delete(MASTER_TOKEN_NAME, -1, cellName, boxName, colName, entityType,
userDataId);
EntityTypeUtils.delete(colName, MASTER_TOKEN_NAME, MediaType.APPLICATION_JSON, entityType, boxName,
cellName, -1);
DavResourceUtils.deleteCollection(cellName, boxName, colName, MASTER_TOKEN_NAME, -1);
BoxUtils.delete(cellName, MASTER_TOKEN_NAME, boxName, -1);
CellUtils.delete(MASTER_TOKEN_NAME, cellName, -1);
}
}
/**
* Elasticsearchから指定のデータを検索する.
* @param indexName インデックス名
* @param esTypeName ESのtype名
* @param routingId ESのルーティングID
* @param searchFieldName ES検索条件のフィールド名("untouched"は不要)
* @param searchFieldValue ES検索条件の値
* @return 検索結果
*/
@SuppressWarnings("unchecked")
DcSearchHit searchFromEs(String indexName,
String esTypeName,
String routingId,
String searchFieldName,
String searchFieldValue) {
EsType type = EsModel.type(indexName, esTypeName, routingId, 0, 0);
String query = "{"
+ " \"query\": {"
+ " \"filtered\": {"
+ " \"query\": {\"match_all\": {}},"
+ " \"filter\": {\"term\": {"
+ " \"s." + searchFieldName + ".untouched\": \"" + searchFieldValue + "\""
+ " }}"
+ " }"
+ " }, "
+ " \"size\": 1"
+ "}";
DcSearchResponse esResponse;
try {
esResponse = type.search((Map<String, Object>) new JSONParser().parse(query));
assertEquals("Failed to retrieve test data from Elasticsearch.", 1, esResponse.getHits().getCount());
DcSearchHit esHit = esResponse.getHits().getAt(0);
return esHit;
} catch (ParseException e) {
fail("Failed to parse query for ES. " + e.getMessage());
}
return null;
}
/**
* Ads書込み失敗ログ出力.
* @param loginfo リペア用のエラー情報
*/
protected void recordAdsWriteFailureLog(AdsWriteFailureLogInfo loginfo) {
AdsWriteFailureLogWriter adsWriteFailureLogWriter = AdsWriteFailureLogWriter.getInstance(
DcCoreConfig.getAdsWriteFailureLogDir(),
DcCoreConfig.getCoreVersion(),
DcCoreConfig.getAdsWriteFailureLogPhysicalDelete());
try {
adsWriteFailureLogWriter.writeActiveFile(loginfo);
} catch (AdsWriteFailureLogException e2) {
DcCoreLog.Server.WRITE_ADS_FAILURE_LOG_ERROR.reason(e2).writeLog();
DcCoreLog.Server.WRITE_ADS_FAILURE_LOG_INFO.params(loginfo.toString());
}
}
}