package io.kaif.service.impl; import static java.util.stream.Collectors.*; import static org.junit.Assert.*; import java.time.Clock; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.Comparator; import java.util.List; import java.util.Random; import java.util.stream.IntStream; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import io.kaif.flake.FlakeId; import io.kaif.model.account.Account; import io.kaif.model.vote.HonorRoll; import io.kaif.model.vote.HonorRollDao; import io.kaif.model.vote.HonorRollVoter; import io.kaif.model.zone.Zone; import io.kaif.model.zone.ZoneInfo; import io.kaif.test.DbIntegrationTests; public class HonorRollServiceImplTest extends DbIntegrationTests { public static final ZoneId BUCKET_ZONE = ZoneId.of("Asia/Taipei"); @Autowired HonorRollServiceImpl service; @Autowired private HonorRollDao honorRollDao; private ZoneInfo zoneInfo; private Account citizen; @Before public void setUp() throws Exception { zoneInfo = savedZoneDefault("pic"); citizen = savedAccountCitizen("citizen1"); service.setClock(Clock.systemDefaultZone()); honorRollDao.evictAllCaches(); } HonorRollVoter increaseArticleVoter(FlakeId flakeId, Zone zone) { return new HonorRollVoter.Builder(citizen.getAccountId(), flakeId, zone, citizen.getUsername()).withDeltaArticleUpVoted(1).build(); } @Test public void listRotateVoteStats() { Instant instant = LocalDate.of(2015, 3, 12).atStartOfDay(BUCKET_ZONE).toInstant(); Clock clock = Clock.fixed(instant, BUCKET_ZONE); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(instant.toEpochMilli()), zoneInfo.getZone())); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(instant.toEpochMilli() + 1), zoneInfo.getZone())); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(instant.toEpochMilli() + 2), savedZoneDefault("pro").getZone())); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(instant.toEpochMilli() + 3), savedZoneDefault("abc").getZone())); service.setClock(clock); List<HonorRoll> honorRolls = service.listHonorRollsByUsername(citizen.getUsername()); assertEquals(3, honorRolls.size()); HonorRoll firstStats = honorRolls.get(0); assertEquals("abc", firstStats.getZone().value()); assertEquals("2015-03-01", firstStats.getBucket()); HonorRoll secondStats = honorRolls.get(1); assertEquals(2, secondStats.getArticleUpVoted()); assertEquals("citizen1", secondStats.getUsername()); assertEquals("pic", secondStats.getZone().value()); HonorRoll thirdStats = honorRolls.get(2); assertEquals(1, thirdStats.getArticleUpVoted()); assertEquals("pro", thirdStats.getZone().value()); service.setClock(Clock.fixed(LocalDate.of(2015, 2, 12).atStartOfDay(BUCKET_ZONE).toInstant(), BUCKET_ZONE)); assertEquals(0, service.listHonorRollsByUsername(citizen.getUsername()).size()); } @Test public void listHonorAllByUsername() { Instant instant = LocalDate.of(2015, 3, 12).atStartOfDay(BUCKET_ZONE).toInstant(); Clock clock = Clock.fixed(instant, BUCKET_ZONE); service.setClock(clock); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(instant.toEpochMilli()), zoneInfo.getZone())); Zone zoneAbc = savedZoneDefault("abc").getZone(); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(instant.toEpochMilli() + 3), zoneAbc)); Instant nextMonth = LocalDate.of(2015, 4, 9).atStartOfDay(BUCKET_ZONE).toInstant(); honorRollDao.updateRotateVoteStats(increaseArticleVoter(FlakeId.endOf(nextMonth.toEpochMilli() + 4), zoneAbc)); List<HonorRoll> honorRolls = service.listHonorAllByUsername(citizen.getUsername()); assertEquals(2, honorRolls.size()); HonorRoll firstStats = honorRolls.get(0); assertEquals(2, firstStats.getArticleUpVoted()); assertEquals("abc", firstStats.getZone().value()); HonorRoll secondStats = honorRolls.get(1); assertEquals(1, secondStats.getArticleUpVoted()); assertEquals("citizen1", secondStats.getUsername()); } @Test public void listHonorRoll() { Instant instant = LocalDate.of(2015, 3, 12).atStartOfDay(BUCKET_ZONE).toInstant(); Clock clock = Clock.fixed(instant, BUCKET_ZONE); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(citizen.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), zoneInfo.getZone(), citizen.getUsername()).withDeltaArticleUpVoted(10) .withDeltaDebateUpVoted(5) .withDeltaDebateDownVoted(3) .build()); Account citizen2 = savedAccountCitizen("king"); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(citizen2.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), zoneInfo.getZone(), citizen2.getUsername()).withDeltaArticleUpVoted(3) .withDeltaDebateUpVoted(2) .withDeltaDebateDownVoted(3) .build()); service.setClock(clock); List<HonorRoll> honorRoll = service.listHonorRollsByZone(zoneInfo.getZone()); assertEquals(2, honorRoll.size()); assertEquals("citizen1", honorRoll.get(0).getUsername()); assertEquals(12, honorRoll.get(0).getHonorScore()); assertEquals("king", honorRoll.get(1).getUsername()); assertEquals(2, honorRoll.get(1).getHonorScore()); service.setClock(Clock.fixed(LocalDate.of(2015, 4, 1).atStartOfDay(BUCKET_ZONE).toInstant(), BUCKET_ZONE)); assertEquals(0, service.listHonorRollsByZone(zoneInfo.getZone()).size()); } @Test public void listHonorRoll_top() { Instant instant = LocalDate.of(2015, 3, 12).atStartOfDay(BUCKET_ZONE).toInstant(); Clock clock = Clock.fixed(instant, BUCKET_ZONE); Random random = new Random(); Comparator<HonorRollVoter> comparator = Comparator.comparing(voter -> voter.getDeltaArticleUpVoted() + voter.getDeltaDebateUpVoted() - voter.getDeltaDebateDownVoted()); List<HonorRollVoter> allStats = IntStream.rangeClosed(1, 100).mapToObj(index -> { Account account = savedAccountCitizen("user-" + index); HonorRollVoter voter = new HonorRollVoter.Builder(account.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), zoneInfo.getZone(), account.getUsername()).withDeltaArticleUpVoted(random.nextInt(100)) .withDeltaDebateUpVoted(random.nextInt(100)) .withDeltaDebateDownVoted(random.nextInt(100)) .build(); honorRollDao.updateRotateVoteStats(voter); return voter; }).sorted(comparator.reversed().thenComparing(HonorRollVoter::getUsername)).collect(toList()); service.setClock(clock); List<HonorRoll> honorRoll = service.listHonorRollsByZone(zoneInfo.getZone()); assertEquals(allStats.stream().limit(25).map(HonorRollVoter::getUsername).collect(toList()), honorRoll.stream().map(HonorRoll::getUsername).collect(toList())); } @Test public void listHonorRoll_all() { Instant instant = LocalDate.of(2015, 3, 12).atStartOfDay(BUCKET_ZONE).toInstant(); Clock clock = Clock.fixed(instant, BUCKET_ZONE); Account a1 = savedAccountCitizen("user-1"); Account a2 = savedAccountCitizen("user-2"); Account a3 = savedAccountCitizen("user-3"); ZoneInfo z1 = savedZoneDefault("java"); ZoneInfo z2 = savedZoneDefault("rails"); ZoneInfo z3 = savedZoneDefault("pypypy"); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(a1.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), z1.getZone(), a1.getUsername()).withDeltaArticleUpVoted(3).withDeltaDebateUpVoted(2).build()); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(a1.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), z2.getZone(), a1.getUsername()).withDeltaArticleUpVoted(1).withDeltaDebateUpVoted(3).build()); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(a2.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), z2.getZone(), a2.getUsername()).withDeltaArticleUpVoted(1).withDeltaDebateUpVoted(1).build()); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(a2.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), z3.getZone(), a2.getUsername()).withDeltaDebateDownVoted(3).build()); honorRollDao.updateRotateVoteStats(new HonorRollVoter.Builder(a3.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), z3.getZone(), a3.getUsername()).withDeltaArticleUpVoted(3).withDeltaDebateUpVoted(200).build()); service.setClock(clock); List<HonorRoll> honorRoll = service.listHonorRollsByZone(null); HonorRoll first = honorRoll.get(0); assertEquals(203, first.getHonorScore()); assertEquals("user-3", first.getUsername()); HonorRoll second = honorRoll.get(1); assertEquals(9, second.getHonorScore()); assertNull(second.getZone()); assertEquals("user-1", second.getUsername()); HonorRoll third = honorRoll.get(2); assertEquals(-1, third.getHonorScore()); assertEquals("user-2", third.getUsername()); assertNull(third.getZone()); } @Test public void listHonorRoll_same_score_order_by_name() { Instant instant = LocalDate.of(2015, 3, 12).atStartOfDay(BUCKET_ZONE).toInstant(); Clock clock = Clock.fixed(instant, BUCKET_ZONE); Comparator<HonorRollVoter> comparator = Comparator.comparing(voter -> voter.getDeltaArticleUpVoted() + voter.getDeltaDebateUpVoted() - voter.getDeltaDebateDownVoted()); List<HonorRollVoter> allStats = IntStream.rangeClosed(1, 25).mapToObj(index -> { Account account = savedAccountCitizen("user-" + index); HonorRollVoter voter = new HonorRollVoter.Builder(account.getAccountId(), FlakeId.endOf(instant.toEpochMilli()), zoneInfo.getZone(), account.getUsername()).withDeltaArticleUpVoted(10).build(); honorRollDao.updateRotateVoteStats(voter); return voter; }).sorted(comparator.reversed().thenComparing(HonorRollVoter::getUsername)).collect(toList()); service.setClock(clock); List<HonorRoll> honorRoll = service.listHonorRollsByZone(zoneInfo.getZone()); assertEquals(allStats.stream().limit(25).map(HonorRollVoter::getUsername).collect(toList()), honorRoll.stream().map(HonorRoll::getUsername).collect(toList())); } }