package gaej2011.service;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import gaej2011.model.Minutes;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import org.junit.Test;
import org.slim3.datastore.Datastore;
import org.slim3.memcache.Memcache;
import org.slim3.tester.AppEngineTestCase;
import org.slim3.tester.TestEnvironment;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.prospectivesearch.ProspectiveSearchPb;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.api.ApiProxy.ApiConfig;
import com.google.apphosting.api.ApiProxy.ApiProxyException;
import com.google.apphosting.api.ApiProxy.Delegate;
import com.google.apphosting.api.ApiProxy.Environment;
import com.google.apphosting.api.ApiProxy.LogRecord;
public class MinutesServiceTest extends AppEngineTestCase {
@Test
public void 議事録のタイトルを作成できる() {
// test@example.com というユーザがログイン中、という状態を作っておく。
TestEnvironment environment =
(TestEnvironment) ApiProxy.getCurrentEnvironment();
environment.setEmail("test@example.com");
// テスト対象を実行する前のMinutes の件数を保存
int before = tester.count(Minutes.class);
// テスト対象を実行する
Key key = MinutesService.put(" テスト用議事録");
// Minutes の件数が一件増えたことを確認する。
int after = tester.count(Minutes.class);
assertThat("Minutes が一件増える", after, is(before + 1));
// 保存されたMinutes のtitle, createdAt, author に値が格納されていることを確認する。
Minutes minutes = Datastore.get(Minutes.class, key);
assertThat(minutes, is(notNullValue()));
assertThat("title が設定される", minutes.getTitle(), is(" テスト用議事録"));
assertThat(
"createdAt が設定される",
minutes.getCreatedAt(),
is(notNullValue()));
assertThat("author が設定される", minutes.getAuthor(), is(notNullValue()));
}
@Test
public void 議事録の一覧を新しい順に表示できる() {
Calendar calendar = Calendar.getInstance();
for (int i = 0; i < 5; i++) { // 5 件保存しておく
Minutes minutes = new Minutes();
minutes.setTitle(" テスト用議事録" + i);
minutes.setCreatedAt(calendar.getTime());
Datastore.put(minutes);
calendar.add(Calendar.HOUR_OF_DAY, 1); // 1 時間進める
}
int count = 0;
Date before = null;
List<Minutes> list = MinutesService.list();
for (Minutes minutes : list) {
Date createdAt = minutes.getCreatedAt();
if (before != null) {
assertThat(
" 新しいものから取得できている",
before.compareTo(createdAt) > 0,
is(true));
}
before = createdAt;
count++;
}
assertThat(" 全てのエンティティが取得できている", count, is(5));
}
@Test
public void 議事録の一覧を取得する際にキャッシュを利用する() {
long before = Memcache.statistics().getHitCount();
MinutesService.list();
long after1 = Memcache.statistics().getHitCount();
assertThat(" 一回目はキャッシュが効かない", after1, is(before));
MinutesService.list();
long after2 = Memcache.statistics().getHitCount();
assertThat(" 二回目はキャッシュが効く", after2, is(before + 1));
}
@Test
public void 議事録登録後にキャッシュが削除される() {
Memcache.put(MinutesService.MEMCACHE_KEY_LIST, "dummy");
assertThat(
" キャッシュが存在している",
Memcache.contains(MinutesService.MEMCACHE_KEY_LIST),
is(true));
MinutesService.put(" テスト用議事録");
assertThat(
" キャッシュが消えている",
Memcache.contains(MinutesService.MEMCACHE_KEY_LIST),
is(false));
}
@Test
public void メモ件数を加算する() {
Key minutesKey = MinutesService.put(" テスト用議事録1");
Memcache.put(MinutesService.MEMCACHE_KEY_LIST, "dummy");
Minutes before = Datastore.get(Minutes.class, minutesKey);
MinutesService.incrementMemoCount(minutesKey);
Minutes after = Datastore.get(Minutes.class, minutesKey);
assertThat(
" メモ件数が1 増える",
after.getMemoCount(),
is(before.getMemoCount() + 1));
assertThat(" 更新日時が設定される", after.getUpdatedAt(), is(notNullValue()));
assertThat(
" 議事録一覧のキャッシュがクリアされる",
Memcache.contains(MinutesService.MEMCACHE_KEY_LIST),
is(false));
}
@Test
public void メモ件数を数えて保存するための更新対象を抽出する() {
List<Key> minutesKeys = new ArrayList<Key>();
Calendar calendar = Calendar.getInstance();
for (int i = 0; i < 6; i++) { // 6 件保存しておく
Minutes minutes = new Minutes();
minutes.setTitle(" テスト用議事録" + i);
minutes.setCreatedAt(calendar.getTime());
minutes.setUpdatedAt(calendar.getTime());
Datastore.put(minutes);
minutesKeys.add(minutes.getKey());
calendar.add(Calendar.HOUR_OF_DAY, -12); // 12 時間戻す
}
// 0: 現在, 1:-12h, 2:-24h, 3:-36h, 4:-48h, 5:-60h
// 2, 3 が対象になるべき。
List<Key> list = MinutesService.queryForUpdateMemoCount();
assertThat("2 つの議事録が返る", list.size(), is(2));
}
@Test
public void 議事録のエンティティにメモエンティティの数を保存する() {
Key minutesKey = MinutesService.put(" テスト用議事録");
for (int i = 0; i < 5; i++) {
MemoService.put(minutesKey, "memo" + i);
}
Memcache.put(MinutesService.MEMCACHE_KEY_LIST, "dummy");
Minutes before = Datastore.get(Minutes.class, minutesKey);
assertThat(" 実行前のメモ数は0", before.getMemoCount(), is(0));
MinutesService.updateMemoCount(minutesKey);
Minutes after = Datastore.get(Minutes.class, minutesKey);
assertThat(" メモ数が5 になる", after.getMemoCount(), is(5));
assertThat(
" 議事録一覧のキャッシュがクリアされる",
Memcache.contains(MinutesService.MEMCACHE_KEY_LIST),
is(false));
}
@Test
public void 議事録を削除する() {
Key minutesKey = MinutesService.put(" テスト用議事録");
for (int i = 0; i < 5; i++) {
MemoService.put(minutesKey, "memo" + i);
}
assertThat(" 実行前のメモ数は5", MemoService.list(minutesKey).size(), is(5));
int beforeMinutesCount = MinutesService.list().size();
Minutes minutes = Datastore.get(Minutes.class, minutesKey);
MinutesService.deleteMinutes(minutes);
assertThat(" メモが全て削除される", MemoService.list(minutesKey).size(), is(0));
assertThat(
" 議事録が削除される",
Datastore.getOrNull(minutesKey),
is(nullValue()));
assertThat(
" 議事録の一覧が一件減っている",
MinutesService.list().size(),
is(beforeMinutesCount - 1));
}
@Test
public void 議事録をTSVに変換する() throws IOException {
// test@example.com というユーザがログイン中、という状態を作っておく。
TestEnvironment environment =
(TestEnvironment) ApiProxy.getCurrentEnvironment();
environment.setEmail("test@example.com");
Key minutesKey = MinutesService.put(" テスト用議事録");
for (int i = 0; i < 5; i++) {
MemoService.put(minutesKey, "memo" + i);
}
assertThat(" 実行前のメモ数は5", MemoService.list(minutesKey).size(), is(5));
Minutes minutes = Datastore.get(Minutes.class, minutesKey);
BlobKey blobKey = MinutesService.exportAsTSV(minutes);
assertThat("blobKey が返される", blobKey, is(notNullValue()));
File file =
new File("www-test/WEB-INF/appengine-generated/"
+ blobKey.getKeyString());
assertThat(" ファイルが作成される", file.exists(), is(true));
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
int index = 0;
while ((line = reader.readLine()) != null) {
String[] split = line.split("\t");
assertThat(split.length, is(3));
assertThat(index + " 行目: 投稿者", split[1], is("\"test@example.com\""));
assertThat(index + " 行目: 内容", split[2], is("\""
+ "memo"
+ index
+ "\""));
index++;
}
}
@Test
public void メモ件数を加算した際にProspectiveSearchを実行する() {
Key minutesKey = MinutesService.put(" テスト用議事録1");
MinutesService.incrementMemoCount(minutesKey);
assertThat(
"PropectiveSearch のmatch() が実行されていてる",
delegate.matchWasExecuted,
is(true));
}
ProspectiveSearchDelegate delegate;
@Override
public void setUp() throws Exception {
super.setUp();
delegate = new ProspectiveSearchDelegate();
ApiProxy.setDelegate(delegate);
}
@Override
public void tearDown() throws Exception {
ApiProxy.setDelegate(delegate.parent);
super.tearDown();
}
static class ProspectiveSearchDelegate implements Delegate<Environment> {
@SuppressWarnings("unchecked")
final Delegate<Environment> parent = ApiProxy.getDelegate();
public void flushLogs(Environment environment) {
parent.flushLogs(environment);
}
public List<Thread> getRequestThreads(Environment environment) {
return parent.getRequestThreads(environment);
}
public void log(Environment environment, LogRecord record) {
parent.log(environment, record);
}
public Future<byte[]> makeAsyncCall(Environment environment,
String packageName, String methodName, byte[] request,
ApiConfig apiConfig) {
return parent.makeAsyncCall(
environment,
packageName,
methodName,
request,
apiConfig);
}
boolean matchWasExecuted = false;
public byte[] makeSyncCall(Environment environment, String packageName,
String methodName, byte[] request) throws ApiProxyException {
if (packageName.equals("matcher") && methodName.equals("Match")) {
matchWasExecuted = true;
ProspectiveSearchPb.MatchResponse responsePb =
new ProspectiveSearchPb.MatchResponse();
return responsePb.toByteArray();
} else {
return parent.makeSyncCall(
environment,
packageName,
methodName,
request);
}
}
}
}