package io.kaif.service.impl;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.*;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import io.kaif.flake.FlakeId;
import io.kaif.model.account.Account;
import io.kaif.model.account.AccountDao;
import io.kaif.model.account.AccountStats;
import io.kaif.model.article.Article;
import io.kaif.model.article.ArticleContentType;
import io.kaif.model.article.ArticleDao;
import io.kaif.model.debate.Debate;
import io.kaif.model.debate.DebateContentType;
import io.kaif.model.debate.DebateDao;
import io.kaif.model.zone.Zone;
import io.kaif.model.zone.ZoneInfo;
import io.kaif.service.AccountService;
import io.kaif.service.FeedService;
import io.kaif.service.ZoneService;
import io.kaif.test.DbIntegrationTests;
import io.kaif.web.support.AccessDeniedException;
public class ArticleServiceImplTest extends DbIntegrationTests {
@Autowired
private ArticleServiceImpl service;
@Autowired
private AccountService accountService;
@Autowired
private DebateDao debateDao;
@Autowired
private ArticleDao articleDao;
@Autowired
private FeedService feedService;
@Autowired
private ZoneService zoneService;
@Autowired
private AccountDao accountDao;
private ZoneInfo zoneInfo;
private Article article;
private Account citizen;
@Before
public void setUp() throws Exception {
zoneInfo = savedZoneDefault("pic");
citizen = savedAccountCitizen("citizen1");
article = savedArticle(zoneInfo, citizen, "art-1");
}
@Test
public void debate() throws Exception {
Account debater = savedAccountCitizen("debater1");
Debate created = service.debate(article.getArticleId(),
Debate.NO_PARENT,
debater,
"pixel art is *better*");
Debate debate = service.loadDebateWithoutCache(created.getDebateId());
assertEquals(DebateContentType.MARK_DOWN, debate.getContentType());
assertEquals(citizen.getAccountId(), debate.getReplyToAccountId());
assertEquals("debater1", debate.getDebaterName());
assertEquals(debater.getAccountId(), debate.getDebaterId());
assertFalse(debate.hasParent());
assertFalse(debate.isMaxLevel());
assertEquals(1, debate.getLevel());
assertEquals("pixel art is *better*", debate.getContent());
assertEquals(0L, debate.getDownVote());
assertEquals(0L, debate.getUpVote());
assertNotNull(debate.getCreateTime());
assertNotNull(debate.getLastUpdateTime());
assertEquals(1, service.findArticle(article.getArticleId()).get().getDebateCount());
assertEquals(1, accountService.loadAccountStats(debater.getUsername()).getDebateCount());
}
@Test
public void debate_replyFeed() throws Exception {
service.debate(article.getArticleId(),
Debate.NO_PARENT,
citizen,
"reply to self article has no feed");
assertEquals(0, feedService.listFeeds(citizen, null).size());
Account debater = savedAccountCitizen("debater1");
Debate debate = service.debate(article.getArticleId(),
Debate.NO_PARENT,
debater,
"some one reply to my article");
assertEquals(debate.getDebateId(), feedService.listFeeds(citizen, null).get(0).getAssetId());
Debate respone = service.debate(article.getArticleId(),
debate.getDebateId(),
citizen,
"author reply me");
assertEquals(respone.getDebateId(), feedService.listFeeds(debater, null).get(0).getAssetId());
}
@Test
public void listLatestDebates() throws Exception {
assertEquals(0, service.listLatestDebates(null).size());
Debate d1 = savedDebate(null);
Debate d2 = savedDebate(null);
assertEquals(asList(d2, d1), service.listLatestDebates(null));
assertEquals(asList(d1), service.listLatestDebates(d2.getDebateId()));
}
@Test
public void listLatestZoneDebates() throws Exception {
assertEquals(0, service.listLatestZoneDebates(zoneInfo.getZone(), null).size());
Debate d1 = savedDebate(article, "foo-12345", null);
Debate d2 = savedDebate(article, "foo-12345", null);
assertEquals(asList(d2, d1), service.listLatestZoneDebates(zoneInfo.getZone(), null));
assertEquals(asList(d1), service.listLatestZoneDebates(zoneInfo.getZone(), d2.getDebateId()));
}
@Test
public void listArticlesByDebatesWithCache_paging() throws Exception {
assertEquals(0, service.listArticlesByDebatesWithCache(Collections.emptyList()).size());
Article a2 = savedArticle(zoneInfo, citizen, "another article");
Debate d1 = savedDebate(article, "foo-12345", null);
Debate d2 = savedDebate(a2, "foo-about", null);
Debate d3 = savedDebate(a2, "foo-duplicate", null);
List<Article> articles = service.listArticlesByDebatesWithCache(asList(d1.getDebateId(),
d2.getDebateId(),
d3.getDebateId()));
assertEquals(2, articles.size());
assertTrue(articles.containsAll(asList(article, a2)));
}
@Test
public void listArticlesByDebatesWithCache_caching() throws Exception {
assertEquals(0, service.listArticlesByDebatesWithCache(Collections.emptyList()).size());
Article a2 = savedArticle(zoneInfo, citizen, "another article");
Debate d1 = savedDebate(article, "foo-12345", null);
Debate d2 = savedDebate(a2, "foo-about", null);
List<Article> articles = service.listArticlesByDebatesWithCache(asList(d1.getDebateId(),
d2.getDebateId()));
List<Article> articles2 = service.listArticlesByDebatesWithCache(asList(d1.getDebateId(),
d2.getDebateId()));
assertSame(articles2.get(0), articles.get(0));
assertSame(articles2.get(1), articles.get(1));
articleDao.evictAllCaches();
List<Article> refreshed = service.listArticlesByDebatesWithCache(asList(d2.getDebateId()));
assertNotSame(refreshed.get(0), articles2.get(1));
}
@Test
public void listDebatesByIdWithCache_paging() throws Exception {
assertEquals(0, service.listDebatesByIdWithCache(Collections.emptyList()).size());
Debate d1 = savedDebate(article, "foo-12345", null);
Debate d2 = savedDebate(article, "foo-about", null);
Debate d3 = savedDebate(article, "foo-duplicate", null);
assertThat(service.listDebatesByIdWithCache(asList(d1.getDebateId(), d2.getDebateId())),
Matchers.hasItems(d1, d2));
assertThat(service.listDebatesByIdWithCache(asList(d3.getDebateId(), d2.getDebateId())),
Matchers.hasItems(d3, d2));
}
@Test
public void listDebatesByIdWithCache_caching() throws Exception {
assertEquals(0, service.listDebatesByIdWithCache(Collections.emptyList()).size());
Debate d1 = debateDao.create(article, null, "foo-12345", citizen, Instant.now());
List<Debate> loaded = service.listDebatesByIdWithCache(asList(d1.getDebateId()));
assertEquals(asList(d1), loaded);
assertSame(loaded.get(0), service.listDebatesByIdWithCache(asList(d1.getDebateId())).get(0));
service.updateDebateContent(d1.getDebateId(), citizen, "new content");
assertEquals("new content",
service.listDebatesByIdWithCache(asList(d1.getDebateId())).get(0).getContent());
}
@Test
public void listRssWithCache() throws Exception {
List<Article> articleList = service.listRssHotZoneArticlesWithCache(zoneInfo.getZone());
assertSame(articleList, service.listRssHotZoneArticlesWithCache(zoneInfo.getZone()));
Zone otherZone = savedZoneDefault("others").getZone();
assertNotSame(articleList, service.listRssHotZoneArticlesWithCache(otherZone));
assertNotSame(articleList, service.listRssTopArticlesWithCache());
}
@Test
public void loadDebateWithCache() throws Exception {
try {
service.loadDebateWithCache(nextFlakeId());
fail("EmptyResultDataAccessException expected");
} catch (EmptyResultDataAccessException expected) {
}
Account debater = savedAccountCitizen("debater1");
Debate created = service.debate(article.getArticleId(),
Debate.NO_PARENT,
debater,
"pixel art is better");
Debate cached = service.loadDebateWithCache(created.getDebateId());
assertEquals(created, cached);
assertSame("cached should be same instance",
cached,
service.loadDebateWithCache(created.getDebateId()));
service.updateDebateContent(created.getDebateId(), debater, "updated content");
assertEquals("updated content",
service.loadDebateWithCache(created.getDebateId()).getContent());
}
@Test
public void listBestDebates_one_level() throws Exception {
Zone zone = zoneInfo.getZone();
FlakeId articleId = article.getArticleId();
assertEquals(0, service.listBestDebates(articleId, null).depthFirst().count());
List<Debate> debates = IntStream.rangeClosed(1, 3)
.mapToObj(i -> service.debate(articleId, Debate.NO_PARENT, citizen, "debate-content-" + i))
.collect(toList());
assertEquals(debates, service.listBestDebates(articleId, null).depthFirst().collect(toList()));
}
@Test
public void listBestDebates_tree() throws Exception {
Debate d1 = savedDebate(null);
Debate d1_1 = savedDebate(d1);
Debate d1_1_1 = savedDebate(d1_1);
Debate d2 = savedDebate(null);
Debate d2_1 = savedDebate(d2);
Debate d2_2 = savedDebate(d2);
// begin out or order
Debate d1_1_2 = savedDebate(d1_1);
Debate d3 = savedDebate(null);
Debate d2_1_1 = savedDebate(d2_1);
Debate d3_1 = savedDebate(d3);
Debate d1_2 = savedDebate(d1);
//make d3_1 best
debateDao.changeTotalVote(d3_1.getDebateId(), 100, 0);
List<Debate> expect = asList(//
d3, d3_1,//
d1, d1_1, d1_1_1, d1_1_2, d1_2, //
d2, d2_1, d2_1_1, d2_2 //
);
assertEquals(expect,
service.listBestDebates(article.getArticleId(), null).depthFirst().collect(toList()));
}
@Test
public void listChildDebates() throws Exception {
Debate d1 = savedDebate(null);
Debate d1_1 = savedDebate(d1);
Debate d1_1_1 = savedDebate(d1_1);
// begin out or order
Debate d1_1_2 = savedDebate(d1_1);
List<Debate> expect = asList(d1_1_1, d1_1_2);
assertEquals(expect,
service.listBestDebates(article.getArticleId(), d1_1.getDebateId())
.depthFirst()
.collect(toList()));
}
private Debate savedDebate(Debate parent) {
return service.debate(article.getArticleId(),
Optional.ofNullable(parent).map(Debate::getDebateId).orElse(Debate.NO_PARENT),
citizen,
"debate-content-" + Math.random());
}
@Test
public void debate_max_level() throws Exception {
Account debater = savedAccountCitizen("debater1");
FlakeId parentId = Debate.NO_PARENT;
Debate last = null;
for (int i = 0; i < 10; i++) {
last = service.debate(article.getArticleId(), parentId, debater, "nested");
parentId = last.getDebateId();
}
assertTrue(last.isMaxLevel());
try {
service.debate(article.getArticleId(), parentId, debater, "failed");
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void debate_reply() throws Exception {
Account debater = savedAccountCitizen("debater1");
Debate l1 = service.debate(article.getArticleId(),
Debate.NO_PARENT,
debater,
"pixel art is better");
Debate l2 = service.debate(article.getArticleId(), l1.getDebateId(), debater, "i think so");
assertEquals(2, l2.getLevel());
assertTrue(l2.hasParent());
assertTrue(l2.isParent(l1));
assertFalse(l1.isParent(l2));
assertEquals(l1.getDebaterId(), l2.getReplyToAccountId());
assertEquals(2, service.findArticle(article.getArticleId()).get().getDebateCount());
Debate l3 = service.debate(article.getArticleId(), l2.getDebateId(), debater, "no no no");
assertEquals(3, l3.getLevel());
assertTrue(l3.hasParent());
assertTrue(l3.isParent(l2));
assertFalse(l2.isParent(l3));
assertEquals(3, service.findArticle(article.getArticleId()).get().getDebateCount());
}
@Test
public void listReplyToDebates() throws Exception {
assertEquals(0, service.listReplyToDebates(citizen, null).size());
Debate l1 = savedDebate(article, "reply to my article", null);
assertEquals(asList(l1), service.listReplyToDebates(citizen, null));
Debate authorReply = service.debate(article.getArticleId(),
Debate.NO_PARENT,
citizen,
"article author reply self is ignored");
savedDebate(article, "not reply to me is ignored", l1);
Debate l2 = savedDebate(article, "a debate reply to me", authorReply);
assertEquals(asList(l2, l1), service.listReplyToDebates(citizen, null));
assertEquals(asList(l1), service.listReplyToDebates(citizen, l2.getDebateId()));
}
@Test
public void listDebatesByDebater() throws Exception {
assertEquals(0, service.listDebatesByDebater(citizen.getUsername(), null).size());
Debate l1 = service.debate(article.getArticleId(), Debate.NO_PARENT, citizen, "debate 1");
Article article2 = savedArticle(zoneInfo, citizen, "another article");
Debate l2 = service.debate(article2.getArticleId(), Debate.NO_PARENT, citizen, "debate 2");
assertEquals(asList(l2, l1), service.listDebatesByDebater(citizen.getUsername(), null));
assertEquals(asList(l1), service.listDebatesByDebater(citizen.getUsername(), l2.getDebateId()));
}
@Test
public void debate_not_enough_authority() throws Exception {
ZoneInfo zoneRequireCitizen = savedZoneDefault("fun");
Article article = savedArticle(zoneRequireCitizen, citizen, "fun-no1");
Account tourist = savedAccountTourist("notActivated");
try {
service.debate(article.getArticleId(), Debate.NO_PARENT, tourist, "pixel art is better");
fail("AccessDeniedException expected");
} catch (AccessDeniedException expected) {
}
}
@Test
public void listLatestZoneArticles() throws Exception {
ZoneInfo zone1 = savedZoneDefault("foo");
ZoneInfo zone2 = savedZoneDefault("zoo");
Article a1 = service.createExternalLink(citizen, zone1.getZone(), "title1", "http://foo1.com");
Article a2 = service.createExternalLink(citizen, zone1.getZone(), "title2", "http://foo2.com");
Article a3 = service.createExternalLink(citizen, zone2.getZone(), "title3", "http://foo2.com");
Article a4 = service.createExternalLink(citizen, zone2.getZone(), "title4", "http://foo2.com");
articleDao.markAsDeleted(a1);
assertEquals(asList(a4, a3, a2, article), service.listLatestArticles(null));
assertEquals(asList(a2, article), service.listLatestArticles(a3.getArticleId()));
}
@Test
public void listLatestArticles() throws Exception {
Account author = savedAccountCitizen("citizen");
ZoneInfo fooZone = savedZoneDefault("foo");
Article a1 = service.createExternalLink(author, fooZone.getZone(), "title1", "http://foo1.com");
Article a2 = service.createExternalLink(author, fooZone.getZone(), "title2", "http://foo2.com");
Article a3 = service.createExternalLink(author, fooZone.getZone(), "title2", "http://foo2.com");
assertEquals(asList(a3, a2, a1), service.listLatestZoneArticles(fooZone.getZone(), null));
assertEquals(singletonList(a1),
service.listLatestZoneArticles(fooZone.getZone(), a2.getArticleId()));
articleDao.markAsDeleted(a1);
assertEquals("listLatest should exclude deleted",
asList(a3, a2),
service.listLatestZoneArticles(fooZone.getZone(), null));
}
@Test
public void listArticlesByAuthor() throws Exception {
Account author = savedAccountCitizen("citizen");
assertEquals(0, service.listArticlesByAuthor(author.getUsername(), null).size());
ZoneInfo fooZone = savedZoneDefault("foo");
Article a1 = service.createExternalLink(author, fooZone.getZone(), "title1", "http://foo1.com");
Article a2 = service.createSpeak(author, fooZone.getZone(), "title2", "good point");
Article a3 = service.createExternalLink(author,
zoneInfo.getZone(),
"title3",
"http://foo2.com");
assertEquals(asList(a3, a2, a1), service.listArticlesByAuthor(author.getUsername(), null));
assertEquals(singletonList(a1),
service.listArticlesByAuthor(author.getUsername(), a2.getArticleId()));
articleDao.markAsDeleted(a1);
assertEquals("listArticlesByUser should exclude deleted",
asList(a3, a2),
service.listArticlesByAuthor(author.getUsername(), null));
}
@Test
public void listHotZoneArticles() throws Exception {
Account author = savedAccountCitizen("citizen");
ZoneInfo fooZone = savedZoneDefault("foo");
List<Article> articles = IntStream.rangeClosed(1, 100).mapToObj(i -> {
Article a = savedArticle(fooZone, author, "title-" + i);
articleDao.changeTotalVote(a.getArticleId(), i * 10, 0);
return a;
}).collect(toList());
Collections.reverse(articles);
List<Article> firstPage = articles.stream().limit(25).collect(toList());
assertEquals(firstPage, service.listHotZoneArticles(fooZone.getZone(), null));
List<Article> secondPage = articles.stream().skip(25).limit(25).collect(toList());
assertEquals(secondPage,
service.listHotZoneArticles(fooZone.getZone(), firstPage.get(24).getArticleId()));
articleDao.markAsDeleted(articles.get(0));
articleDao.markAsDeleted(articles.get(1));
List<Article> firstPageWithoutDeleted = articles.stream().skip(2).limit(25).collect(toList());
assertEquals(firstPageWithoutDeleted, service.listHotZoneArticles(fooZone.getZone(), null));
}
@Test
public void listCachedTopArticles() throws Exception {
List<Article> articles = service.listRssTopArticlesWithCache();
assertSame(articles, service.listRssTopArticlesWithCache());
}
@Test
public void listTopArticles() throws Exception {
Account author = savedAccountCitizen("citizen");
ZoneInfo defaultZone = savedZoneDefault("foo");
List<Article> articles = IntStream.rangeClosed(1, 30).mapToObj(i -> {
Article a = savedArticle(defaultZone, author, "title-" + i);
articleDao.changeTotalVote(a.getArticleId(), i * 10, 0);
return a;
}).collect(toList());
ZoneInfo kaifZone = savedZoneKaif("faq");
//hideFromTop articles will be ignored
savedArticle(kaifZone, author, "title-faq");
Collections.reverse(articles);
//deleted will be ignored
articleDao.markAsDeleted(articles.get(0));
//add article from setUp()
articles.add(article);
List<Article> firstPage = articles.stream().skip(1).limit(25).collect(toList());
List<Article> secondPage = articles.stream().skip(26).collect(toList());
assertEquals(firstPage, service.listTopArticles(null));
assertEquals(secondPage, service.listTopArticles(firstPage.get(24).getArticleId()));
}
@Test
public void deleteArticle_by_author() throws Exception {
assertTrue(service.canDeleteArticle(citizen.getUsername(), article.getArticleId()));
service.deleteArticle(citizen, article.getArticleId());
Zone zone = zoneInfo.getZone();
assertFalse(service.isExternalLinkExist(zone, article.getLink()));
// query single record still return article, not null
assertTrue(service.loadArticle(article.getArticleId()).isDeleted());
assertTrue(service.findArticle(article.getArticleId()).get().isDeleted());
// will excluded in all public articles query
assertThat(service.listArticlesByAuthor(citizen.getUsername(), null), not(hasItem(article)));
assertThat(service.listTopArticles(null), not(hasItem(article)));
assertThat(service.listLatestArticles(null), not(hasItem(article)));
assertThat(service.listLatestZoneArticles(zone, null), not(hasItem(article)));
assertThat(service.listHotZoneArticles(zone, null), not(hasItem(article)));
// 1) RSS article still see deleted articles (stale)
// 2) voted article still see deleted articles, check voteService test
}
@Test
public void deleteArticle_reject_not_author() throws Exception {
Article article = savedArticle(zoneInfo, citizen, "to be delete");
try {
Account other = savedAccountCitizen("misc_user");
assertFalse(service.canDeleteArticle(other.getUsername(), article.getArticleId()));
service.deleteArticle(other, article.getArticleId());
fail("AccessDeniedException expected");
} catch (AccessDeniedException expected) {
}
assertFalse(service.loadArticle(article.getArticleId()).isDeleted());
}
@Test
public void deleteArticle_author_can_not_after_10_minutes() throws Exception {
service.setClock(Clock.offset(Clock.systemDefaultZone(), Duration.ofMinutes(-11)));
Article article = service.createSpeak(citizen, zoneInfo.getZone(), "titleFoo", "contentFoo");
try {
service.setClock(Clock.systemDefaultZone());
assertFalse(service.canDeleteArticle(citizen.getUsername(), article.getArticleId()));
service.deleteArticle(citizen, article.getArticleId());
fail("AccessDeniedException expected");
} catch (AccessDeniedException expected) {
}
assertFalse(service.loadArticle(article.getArticleId()).isDeleted());
}
@Test
public void deleteArticle_zone_admin() throws Exception {
Account admin = savedAccountCitizen("admin");
accountDao.changeTotalVotedDebate(admin.getAccountId(), 1000, 0);
ZoneInfo aZone = zoneService.createByUser("a-zone", "a-zone", admin);
service.setClock(Clock.offset(Clock.systemDefaultZone(), Duration.ofMinutes(11)));
Article article = service.createSpeak(citizen, aZone.getZone(), "titleFoo", "contentFoo");
service.setClock(Clock.systemDefaultZone());
assertTrue(service.canDeleteArticle(admin.getUsername(), article.getArticleId()));
//admin can delete article without time constraint
service.deleteArticle(admin, article.getArticleId());
assertTrue(service.loadArticle(article.getArticleId()).isDeleted());
}
@Test
public void createExternalLink() throws Exception {
Article created = service.createExternalLink(citizen,
zoneInfo.getZone(),
"title1",
"http://foo.com");
Article article = service.findArticle(created.getArticleId()).get();
assertEquals(zoneInfo.getZone(), article.getZone());
assertEquals("title1", article.getTitle());
assertNotNull(article.getCreateTime());
assertEquals("http://foo.com", article.getLink());
assertNull(article.getContent());
assertEquals(ArticleContentType.NONE, article.getContentType());
assertEquals(citizen.getUsername(), article.getAuthorName());
assertEquals(citizen.getAccountId(), article.getAuthorId());
assertFalse(article.isDeleted());
assertEquals(0, article.getUpVote());
assertEquals(0, article.getDownVote());
assertEquals(0, article.getDebateCount());
assertTrue(article.isExternalLink());
AccountStats stats = accountService.loadAccountStats(citizen.getUsername());
assertEquals(1, stats.getArticleCount());
}
@Test
public void createExternalLink_check_duplicate() throws Exception {
assertFalse(service.isExternalLinkExist(zoneInfo.getZone(), "http://foo.com"));
Article created = service.createExternalLink(citizen,
zoneInfo.getZone(),
"title1",
"http://foo.com");
assertTrue(service.isExternalLinkExist(zoneInfo.getZone(), "http://foo.com"));
assertFalse(service.isExternalLinkExist(zoneInfo.getZone(), "http://foo.not.match"));
assertFalse(service.isExternalLinkExist(Zone.valueOf("other"), "http://foo.com"));
}
@Test
public void listArticlesByExternalLink() throws Exception {
assertEquals(0,
service.listArticlesByExternalLink(zoneInfo.getZone(), "http://foo.com").size());
Article a1 = service.createExternalLink(citizen,
zoneInfo.getZone(),
"title1",
"http://foo.com");
assertEquals(asList(a1),
service.listArticlesByExternalLink(zoneInfo.getZone(), "http://foo.com"));
Article a2 = service.createExternalLink(citizen,
zoneInfo.getZone(),
"title1",
"http://foo.com");
assertEquals(asList(a2, a1),
service.listArticlesByExternalLink(zoneInfo.getZone(), "http://foo.com"));
}
@Test
public void createExternalLink_check_duplicate_canonical() throws Exception {
assertFalse(service.isExternalLinkExist(zoneInfo.getZone(), " http://foo.com "));
Article created = service.createExternalLink(citizen,
zoneInfo.getZone(),
"title1",
"http://foo.com");
assertTrue(service.isExternalLinkExist(zoneInfo.getZone(), " http://foo.com "));
assertTrue(service.isExternalLinkExist(zoneInfo.getZone(), "http://foo.com"));
//remove utm tracking
assertTrue(service.isExternalLinkExist(zoneInfo.getZone(),
"http://foo.com?utm_foo=12&utm_bar=aaa"));
}
@Test
public void canonicalizeUrl() throws Exception {
assertEquals("http://foo.com/", service.canonicalizeUrl("http://foo.com"));
assertEquals("https://foo.com/", service.canonicalizeUrl(" https://foo.com \n \r \t\t"));
assertEquals("http://foo.com/?c=2&d=1#hash",
service.canonicalizeUrl("http://foo.com?d=1&c=2#hash"));
assertEquals("http://foo.com/?xyz",
service.canonicalizeUrl("http://foo.com?utm_foo=12&utm_bar=aaa&xyz"));
assertEquals("/foo", service.canonicalizeUrl("foo"));
assertEquals("ftp://foo.com/", service.canonicalizeUrl("ftp://foo.com"));
}
@Test
public void accountStatsOnlyForCitizenZone() throws Exception {
ZoneInfo touristZone = savedZoneTourist("test");
Account tourist = savedAccountTourist("guestB");
Article article = service.createExternalLink(tourist,
touristZone.getZone(),
"title1",
"http://foo.com");
service.debate(article.getArticleId(), null, tourist, "test article");
AccountStats stats = accountService.loadAccountStats(tourist.getUsername());
assertEquals(0, stats.getArticleCount());
assertEquals(0, stats.getDebateCount());
}
@Test
public void createSpeak() throws Exception {
Article created = service.createSpeak(citizen, zoneInfo.getZone(), "title1", "laugh out loud");
Article article = service.findArticle(created.getArticleId()).get();
assertEquals(zoneInfo.getZone(), article.getZone());
assertEquals("title1", article.getTitle());
assertNotNull(article.getCreateTime());
assertEquals("laugh out loud", article.getContent());
assertNull(article.getLink());
assertEquals(ArticleContentType.MARK_DOWN, article.getContentType());
assertEquals(citizen.getUsername(), article.getAuthorName());
assertEquals(citizen.getAccountId(), article.getAuthorId());
assertFalse(article.isDeleted());
assertEquals(0, article.getUpVote());
assertEquals(0, article.getDownVote());
assertEquals(0, article.getDebateCount());
assertFalse(article.isExternalLink());
AccountStats stats = accountService.loadAccountStats(citizen.getUsername());
assertEquals(1, stats.getArticleCount());
}
@Test
public void createArticle_not_enough_authority() throws Exception {
ZoneInfo zoneRequireCitizen = savedZoneDefault("fun");
Account tourist = savedAccountTourist("notActivated");
try {
service.createExternalLink(tourist, zoneRequireCitizen.getZone(), "title1", "http://foo.com");
fail("AccessDeniedException expected");
} catch (AccessDeniedException expected) {
}
try {
service.createSpeak(tourist, zoneRequireCitizen.getZone(), "title1", "my content 12345");
fail("AccessDeniedException expected");
} catch (AccessDeniedException expected) {
}
}
@Test
public void canCreateArticle() throws Exception {
ZoneInfo zoneRequireCitizen = savedZoneDefault("fun");
Account tourist = savedAccountTourist("notActivated");
assertFalse(service.canCreateArticle(zoneRequireCitizen.getZone(), tourist));
assertTrue(service.canCreateArticle(zoneRequireCitizen.getZone(), citizen));
}
@Test
public void updateDebateContent() throws Exception {
Debate d1 = savedDebate(null);
Thread.sleep(200);
String result = service.updateDebateContent(d1.getDebateId(),
citizen,
"pixel art is better<evil>hi</evil>*hi*");
assertEquals("<p>pixel art is better<evil>hi</evil><em>hi</em></p>\n", result);
Debate updated = service.loadDebateWithoutCache(d1.getDebateId());
assertTrue(updated.isEdited());
assertTrue(updated.getLastUpdateTime().isAfter(d1.getLastUpdateTime()));
}
@Test
public void loadEditableDebate() throws Exception {
Debate d1 = service.debate(article.getArticleId(), Debate.NO_PARENT, citizen, "> a quote");
String content = service.loadEditableDebateContent(d1.getDebateId(), citizen);
assertEquals("> a quote", content);
}
@Test
public void loadEditableDebate_not_editor() throws Exception {
Debate d1 = savedDebate(null);
try {
service.loadEditableDebateContent(d1.getDebateId(), savedAccountCitizen("not-editor"));
fail("AccessDeniedException expected");
} catch (AccessDeniedException expected) {
}
}
}