package org.ryu22e.nico2cal.controller;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.ComponentList;
import net.fortuna.ical4j.model.component.VEvent;
import org.joda.time.DateTime;
import org.junit.Test;
import org.ryu22e.nico2cal.meta.NicoliveIndexMeta;
import org.ryu22e.nico2cal.meta.NicoliveMeta;
import org.ryu22e.nico2cal.model.Nicolive;
import org.ryu22e.nico2cal.model.NicoliveIndex;
import org.slim3.datastore.Datastore;
import org.slim3.memcache.Memcache;
import org.slim3.tester.ControllerTestCase;
import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Link;
import com.google.appengine.api.datastore.Text;
/**
* @author ryu22e
*
*/
public final class CalendarControllerTest extends ControllerTestCase {
/**
*
*/
private List<Key> testDataKeys = new LinkedList<Key>();
/**
*
*/
private void clearDataStore() {
NicoliveMeta n = NicoliveMeta.get();
Datastore.delete(Datastore.query(n).asKeyList());
NicoliveIndexMeta ni = NicoliveIndexMeta.get();
Datastore.delete(Datastore.query(ni).asKeyList());
}
/*
* (non-Javadoc) {@inheritDoc}
*/
@Override
public void setUp() throws Exception {
super.setUp();
NamespaceManager.set("test");
clearDataStore();
// テストデータを登録する。
testDataKeys.clear();
List<Nicolive> nicolives = new LinkedList<Nicolive>();
List<NicoliveIndex> indexes = new LinkedList<NicoliveIndex>();
DateTime datetime = new DateTime();
for (int i = 0; i < 4; i++) {
Nicolive nicolive = new Nicolive();
nicolive.setKey(Datastore.allocateId(NicoliveMeta.get()));
nicolive.setTitle("テスト" + i);
nicolive.setDescription(new Text("テスト説明文" + i));
nicolive.setOpenTime(datetime.minusWeeks(i).toDate());
nicolive.setLink(new Link("http://ryu22e.org/" + i));
nicolives.add(nicolive);
NicoliveIndex index1 = new NicoliveIndex();
index1.setKeyword("テスト");
index1.setNicoliveKey(nicolive.getKey());
indexes.add(index1);
NicoliveIndex index2 = new NicoliveIndex();
index2.setKeyword("説明");
index2.setNicoliveKey(nicolive.getKey());
indexes.add(index2);
NicoliveIndex index3 = new NicoliveIndex();
index3.setKeyword("文");
index3.setNicoliveKey(nicolive.getKey());
indexes.add(index3);
NicoliveIndex index4 = new NicoliveIndex();
index4.setKeyword(Integer.toString(i));
index4.setNicoliveKey(nicolive.getKey());
indexes.add(index4);
}
testDataKeys.addAll(Datastore.put(nicolives));
testDataKeys.addAll(Datastore.put(indexes));
}
/*
* (non-Javadoc) {@inheritDoc}
*/
@Override
public void tearDown() throws Exception {
// テストデータを削除する。
if (0 < testDataKeys.size()) {
Datastore.delete(testDataKeys);
}
super.tearDown();
}
/**
* @throws Exception
*/
@Test
public void バリデーションのテスト_パラメータを指定しない() throws Exception {
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(401));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void バリデーションのテスト_keywordのみを指定() throws Exception {
tester.param("keyword", "テスト");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(401));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void バリデーションのテスト_startWeekが数字以外() throws Exception {
tester.param("startWeek", "invalid");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(401));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
@Test
public void バリデーションのテスト_startWeekが1未満() throws Exception {
tester.param("startWeek", 0);
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(401));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
@Test
public void バリデーションのテスト_startWeekが4を超える() throws Exception {
tester.param("startWeek", 5);
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(401));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void バリデーションのテスト_keywordが最大文字列長を超える() throws Exception {
// エラーになる。
char[] chars = Arrays.copyOf(new char[] { 'あ' }, 51);
String keyword = new String(chars);
tester.param("startWeek", 1);
tester.param("keyword", keyword);
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(401));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void バリデーションのテスト_keywordが最大文字列長と同じ() throws Exception {
// エラーにならない。
char[] chars = Arrays.copyOf(new char[] { 'あ' }, 50);
String keyword = new String(chars);
tester.param("startWeek", 1);
tester.param("keyword", keyword);
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void バリデーションのテスト_keywordが最大文字列長より短い() throws Exception {
// エラーにならない。
char[] chars = Arrays.copyOf(new char[] { 'あ' }, 49);
String keyword = new String(chars);
tester.param("startWeek", 1);
tester.param("keyword", keyword);
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void iCalendarファイルをダウンロードする_該当するデータが存在しない() throws Exception {
tester.param("startWeek", 1);
tester.param("keyword", "存在しないキーワード");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
assertThat(
tester.response.getContentType(),
is("text/calendar;charset=UTF-8"));
String output = tester.response.getOutputAsString();
assertThat(output, is(notNullValue()));
Reader reader = null;
try {
reader = new StringReader(output);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(reader);
assertThat(calendar, is(notNullValue()));
assertThat(
calendar.getProperty("PRODID").getValue(),
is("nico2ical"));
assertThat(calendar.getProperty("VERSION").getValue(), is("2.0"));
assertThat(
calendar.getProperty("X-WR-CALNAME").getValue(),
is("ニコニコ生放送"));
ComponentList components = calendar.getComponents();
assertThat(components, is(notNullValue()));
assertThat(components.size(), is(0));
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* @throws Exception
*/
@Test
public void iCalendarファイルをダウンロードする_startWeekのみを指定する() throws Exception {
tester.param("startWeek", 1);
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void iCalendarファイルをダウンロードする_1週間前以降のデータを取得する() throws Exception {
tester.param("startWeek", 1);
tester.param("keyword", "テスト 説明 文");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
assertThat(
tester.response.getContentType(),
is("text/calendar;charset=UTF-8"));
assertThat(
tester.response.getHeader("Content-Disposition"),
is("filename=\"nico2ical.ics\""));
String output = tester.response.getOutputAsString();
assertThat(output, is(notNullValue()));
Reader reader = null;
try {
reader = new StringReader(output);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(reader);
assertThat(calendar, is(notNullValue()));
assertThat(
calendar.getProperty("PRODID").getValue(),
is("nico2ical"));
assertThat(calendar.getProperty("VERSION").getValue(), is("2.0"));
assertThat(
calendar.getProperty("X-WR-CALNAME").getValue(),
is("ニコニコ生放送"));
ComponentList components = calendar.getComponents();
assertThat(components, is(notNullValue()));
assertThat(components.size(), is(1));
// DTSTARTが古い順にイベントが並んでいる。
int i = 0;
for (Object object : components) {
assertThat(object, is(notNullValue()));
assertThat(object, is(instanceOf(VEvent.class)));
VEvent event = (VEvent) object;
assertThat(event.getSummary().getValue(), is("テスト" + i));
assertThat(event.getDescription().getValue(), is("テスト説明文" + i));
assertThat(event.getUrl().getValue(), is("http://ryu22e.org/"
+ i));
assertThat(event.getStartDate(), is(notNullValue()));
assertThat(event.getEndDate(), is(notNullValue()));
i--;
}
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* @throws Exception
*/
@Test
public void iCalendarファイルをダウンロードする_2週間前以降のデータを取得する() throws Exception {
tester.param("startWeek", 2);
tester.param("keyword", "テスト 説明 文");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
assertThat(
tester.response.getContentType(),
is("text/calendar;charset=UTF-8"));
assertThat(
tester.response.getHeader("Content-Disposition"),
is("filename=\"nico2ical.ics\""));
String output = tester.response.getOutputAsString();
assertThat(output, is(notNullValue()));
Reader reader = null;
try {
reader = new StringReader(output);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(reader);
assertThat(calendar, is(notNullValue()));
assertThat(
calendar.getProperty("PRODID").getValue(),
is("nico2ical"));
assertThat(calendar.getProperty("VERSION").getValue(), is("2.0"));
assertThat(
calendar.getProperty("X-WR-CALNAME").getValue(),
is("ニコニコ生放送"));
ComponentList components = calendar.getComponents();
assertThat(components, is(notNullValue()));
assertThat(components.size(), is(2));
// DTSTARTが古い順にイベントが並んでいる。
int i = 1;
for (Object object : components) {
assertThat(object, is(notNullValue()));
assertThat(object, is(instanceOf(VEvent.class)));
VEvent event = (VEvent) object;
assertThat(event.getSummary().getValue(), is("テスト" + i));
assertThat(event.getDescription().getValue(), is("テスト説明文" + i));
assertThat(event.getUrl().getValue(), is("http://ryu22e.org/"
+ i));
assertThat(event.getStartDate(), is(notNullValue()));
assertThat(event.getEndDate(), is(notNullValue()));
i--;
}
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* @throws Exception
*/
@Test
public void iCalendarファイルをダウンロードする_3週間前以降のデータを取得する() throws Exception {
tester.param("startWeek", 3);
tester.param("keyword", "テスト 説明 文");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
assertThat(
tester.response.getContentType(),
is("text/calendar;charset=UTF-8"));
assertThat(
tester.response.getHeader("Content-Disposition"),
is("filename=\"nico2ical.ics\""));
String output = tester.response.getOutputAsString();
assertThat(output, is(notNullValue()));
Reader reader = null;
try {
reader = new StringReader(output);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(reader);
assertThat(calendar, is(notNullValue()));
assertThat(
calendar.getProperty("PRODID").getValue(),
is("nico2ical"));
assertThat(calendar.getProperty("VERSION").getValue(), is("2.0"));
assertThat(
calendar.getProperty("X-WR-CALNAME").getValue(),
is("ニコニコ生放送"));
ComponentList components = calendar.getComponents();
assertThat(components, is(notNullValue()));
assertThat(components.size(), is(3));
// DTSTARTが古い順にイベントが並んでいる。
int i = 2;
for (Object object : components) {
assertThat(object, is(notNullValue()));
assertThat(object, is(instanceOf(VEvent.class)));
VEvent event = (VEvent) object;
assertThat(event.getSummary().getValue(), is("テスト" + i));
assertThat(event.getDescription().getValue(), is("テスト説明文" + i));
assertThat(event.getUrl().getValue(), is("http://ryu22e.org/"
+ i));
assertThat(event.getStartDate(), is(notNullValue()));
assertThat(event.getEndDate(), is(notNullValue()));
i--;
}
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* @throws Exception
*/
@Test
public void iCalendarファイルをダウンロードする_4週間前以降のデータを取得する() throws Exception {
tester.param("startWeek", 4);
tester.param("keyword", "テスト 説明 文");
tester.start("/Calendar");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
assertThat(
tester.response.getContentType(),
is("text/calendar;charset=UTF-8"));
assertThat(
tester.response.getHeader("Content-Disposition"),
is("filename=\"nico2ical.ics\""));
String output = tester.response.getOutputAsString();
assertThat(output, is(notNullValue()));
Reader reader = null;
try {
reader = new StringReader(output);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(reader);
assertThat(calendar, is(notNullValue()));
assertThat(
calendar.getProperty("PRODID").getValue(),
is("nico2ical"));
assertThat(calendar.getProperty("VERSION").getValue(), is("2.0"));
assertThat(
calendar.getProperty("X-WR-CALNAME").getValue(),
is("ニコニコ生放送"));
ComponentList components = calendar.getComponents();
assertThat(components, is(notNullValue()));
assertThat(components.size(), is(4));
// DTSTARTが古い順にイベントが並んでいる。
int i = 3;
for (Object object : components) {
assertThat(object, is(notNullValue()));
assertThat(object, is(instanceOf(VEvent.class)));
VEvent event = (VEvent) object;
assertThat(event.getSummary().getValue(), is("テスト" + i));
assertThat(event.getDescription().getValue(), is("テスト説明文" + i));
assertThat(event.getUrl().getValue(), is("http://ryu22e.org/"
+ i));
assertThat(event.getStartDate(), is(notNullValue()));
assertThat(event.getEndDate(), is(notNullValue()));
i--;
}
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* @throws Exception
*/
@Test
public void 同じ条件で2回iCalendarファイルをダウンロードする() throws Exception {
String memcacheKey =
"startWeek=1&keyword=" + URLEncoder.encode("テスト 説明 文", "UTF-8");
Memcache.delete(memcacheKey);
tester.param("startWeek", 1);
tester.param("keyword", "テスト 説明 文");
tester.start("/Calendar");
CalendarController controller1 = tester.getController();
assertThat(controller1, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
String output1 = tester.response.getOutputAsString();
Calendar calendar1 = null;
try {
Reader reader = new StringReader(output1);
CalendarBuilder builder = new CalendarBuilder();
calendar1 = builder.build(reader);
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
}
// 取得した内容がキャッシュにも保存されている。
Object cache = Memcache.get(memcacheKey);
assertThat(output1, is(instanceOf(String.class)));
Calendar calendarCache = null;
try {
Reader reader = new StringReader((String) cache);
CalendarBuilder builder = new CalendarBuilder();
calendarCache = builder.build(reader);
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
}
assertThat(calendar1, is(calendarCache));
// 同じ条件でもう一度コントローラーを呼ぶと、キャッシュに保存している内容を取得する。
tester.param("startWeek", 1);
tester.param("keyword", "テスト 説明 文");
tester.start("/Calendar");
CalendarController controller2 = tester.getController();
assertThat(controller2, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
String output2 = tester.response.getOutputAsString();
Calendar calendar2 = null;
try {
Reader reader = new StringReader(output2);
CalendarBuilder builder = new CalendarBuilder();
calendar2 = builder.build(reader);
} catch (IOException e) {
fail(e.getMessage());
} catch (ParserException e) {
fail(e.getMessage());
}
assertThat(calendar2, is(calendarCache));
}
/**
* @throws Exception
*/
@Test
public void urlルーティングのテスト_startWeekのみを指定する() throws Exception {
tester.start("/ical/1");
assertThat(tester.isRedirect(), is(false));
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
/**
* @throws Exception
*/
@Test
public void urlルーティングのテスト_startWeekとkeywordを指定する() throws Exception {
tester.start("/ical/1/test");
CalendarController controller = tester.getController();
assertThat(controller, is(notNullValue()));
assertThat(tester.isRedirect(), is(false));
assertThat(tester.response.getStatus(), is(200));
assertThat(tester.getDestinationPath(), is(nullValue()));
}
}