Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
language: groovy
jdk:
- oraclejdk8
sudo: false
after_success:
- mvn -q -e clean test jacoco:report coveralls:report
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>pl.jug.torun</groupId>
<artifactId>xenia-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>2.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Xenia API</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ final class DrawController {
}

@RequestMapping(method = RequestMethod.GET)
public DrawResult drawWinnerCandidate(@PathVariable("giveAway") GiveAway giveAway, @RequestParam(value = "absent", required = false) Member absentMember) {
public DrawResult drawWinnerCandidate(@PathVariable("giveAway") GiveAway giveAway, @RequestParam(value = "absent", required = false) Member absentMember,
@RequestParam(value = "skipped", required = false) Member skippedMember) {
if (absentMember) {
drawService.markMemberAsAbsentForCurrentDraw(absentMember, giveAway.event)
} else if (skippedMember) {
drawService.setGiveAwaySkippedForMember(skippedMember, giveAway)
}

return drawService.drawWinnerCandidate(giveAway)
Expand Down
19 changes: 17 additions & 2 deletions src/main/groovy/pl/jug/torun/xenia/draw/DrawService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,21 @@ import pl.jug.torun.xenia.events.Event
import pl.jug.torun.xenia.meetup.Member
import pl.jug.torun.xenia.meetup.MemberRepository

import static org.apache.commons.lang.StringUtils.isNotBlank

@Slf4j
@Service
class DrawService {
private final DrawResultRepository drawResultRepository
private final AttendeeRepository attendeeRepository
private final MemberRepository memberRepository
private final SkippedGiveAwayContainer skippedGiveAwayContainer

@Autowired
DrawService(DrawResultRepository drawResultRepository, AttendeeRepository attendeeRepository, MemberRepository memberRepository) {
DrawService(DrawResultRepository drawResultRepository, SkippedGiveAwayContainer skippedGiveAwayContainer, AttendeeRepository attendeeRepository,
MemberRepository memberRepository) {
this.drawResultRepository = drawResultRepository
this.skippedGiveAwayContainer = skippedGiveAwayContainer
this.attendeeRepository = attendeeRepository
this.memberRepository = memberRepository
}
Expand Down Expand Up @@ -53,8 +58,12 @@ class DrawService {
log.debug '{} members have won this prize already...', membersWhoHaveWonThisPrizeAlready.size()
members.removeAll(membersWhoHaveWonThisPrizeAlready)

Set<Member> membersWithSkippedGiveAway = skippedGiveAwayContainer.getMembersByGiveAway(giveAway)
log.debug '{} members have skipped this prize already...', membersWithSkippedGiveAway.size()
members.removeAll(membersWithSkippedGiveAway)

if (giveAway.emailRequired) {
members = members.findAll { it.email != null && !it.email.empty }
members = members.findAll { isNotBlank(it.email) }
}
return members
}
Expand All @@ -77,4 +86,10 @@ class DrawService {
attendeeRepository.save(attendee)
}
}

public void setGiveAwaySkippedForMember(Member member, GiveAway giveAway) {
log.debug 'Member {} skipped the draw result for {}', member, giveAway
skippedGiveAwayContainer.addSkippedMember(giveAway, member)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package pl.jug.torun.xenia.draw

import org.springframework.stereotype.Component
import pl.jug.torun.xenia.meetup.Member

import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentSkipListSet

@Component
class SkippedGiveAwayContainer {

private final Map<GiveAway, Set<Member>> skippedGiveWays = new ConcurrentHashMap<>()

Set<Member> getMembersByGiveAway(GiveAway giveaway) {
(skippedGiveWays[giveaway] ?: new HashSet<>()).asImmutable()
}

void addSkippedMember(GiveAway giveAway, Member member) {
skippedGiveWays.computeIfAbsent(giveAway) {
new ConcurrentSkipListSet<Member>({ m1, m2 -> m1.id.compareTo(m2.id) })
}.add(member)
}
}
43 changes: 34 additions & 9 deletions src/test/groovy/pl/jug/torun/xenia/draw/DrawServiceSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import org.joda.time.DateTime
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.test.context.ContextConfiguration
import pl.jug.torun.xenia.events.Attendee
import pl.jug.torun.xenia.events.AttendeeRepository
import pl.jug.torun.xenia.events.Event
import pl.jug.torun.xenia.events.EventRepository
import pl.jug.torun.xenia.events.*
import pl.jug.torun.xenia.meetup.Member
import pl.jug.torun.xenia.meetup.MemberRepository
import pl.jug.torun.xenia.prizes.Prize
Expand All @@ -18,6 +15,8 @@ import spock.lang.Subject

import java.util.concurrent.atomic.AtomicLong

import static org.apache.commons.lang.StringUtils.isNotBlank

@Stepwise
@DataJpaTest
@ContextConfiguration
Expand Down Expand Up @@ -53,7 +52,7 @@ class DrawServiceSpec extends Specification {
private AtomicLong counter = new AtomicLong(0L)

def setup() {
drawService = new DrawService(drawResultRepository, attendeeRepository, memberRepository)
drawService = new DrawService(drawResultRepository, new SkippedGiveAwayContainer(), attendeeRepository, memberRepository)
giveAwayController = new GiveAwayController(giveAwayRepository, prizeRepository, drawResultRepository)
event = event("Test event", DateTime.parse("2015-04-02T20:00:00"))
}
Expand All @@ -80,7 +79,7 @@ class DrawServiceSpec extends Specification {
thrown IllegalStateException
}

def "should confirm that giveaway that requires email can be drawn by attendess with email only"() {
def "should confirm that giveaway that requires email can be drawn by attendees with email only"() {
setup:
GiveAway giveAway = giveAwayWithPrizeAndAmount("License", 1, true)
attendee("John")
Expand All @@ -94,7 +93,7 @@ class DrawServiceSpec extends Specification {
DrawResult result = drawService.drawWinnerCandidate(giveAway)

then:
result.member.email != null && result.member.email != ""
isNotBlank(result.member.email)

where:
i << (1..RANDOM_TESTS_RUN_LIMIT)
Expand Down Expand Up @@ -204,6 +203,21 @@ class DrawServiceSpec extends Specification {
i << (1..RANDOM_TESTS_RUN_LIMIT)
}

def "should not allow attendee who skipped a giveaway to win same prize again during the same event"() {
setup:
GiveAway giveAway = giveAwayWithPrizeAndAmount("Something", 1)
attendee("Paul").with {
drawService.setGiveAwaySkippedForMember(it.member, giveAway)
}
attendee("Roger")

when:
Member winner = drawService.drawWinnerCandidate(giveAway).member

then:
winner.name == "Roger"
}

def "should draw all giveaways and confirm winners"() {
setup:
GiveAway firstGiveAway = giveAwayWithPrizeAndAmount("Spring Boot in Action ebook", 2)
Expand Down Expand Up @@ -247,7 +261,18 @@ class DrawServiceSpec extends Specification {
i << (1..RANDOM_TESTS_RUN_LIMIT)
}

def "should mark attendee as absent"() {
given:
Attendee attendee = attendee("Roger")
when:
drawService.markMemberAsAbsentForCurrentDraw(attendee.member, event)
then:
storedAttendee(attendee).absent
}

private Attendee storedAttendee(Attendee attendee) {
return attendeeRepository.findAllByMemberId(attendee.member.id)[0]
}

private GiveAway giveAwayWithAmount(int amount) {
return giveAwayWithPrizeAndAmount("Test", amount)
Expand All @@ -274,7 +299,7 @@ class DrawServiceSpec extends Specification {
}

private Attendee absent(Attendee attendee) {
attendee.absent = true
return attendeeRepository.save(attendee)
drawService.markMemberAsAbsentForCurrentDraw(attendee.member, event)
return attendee
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package pl.jug.torun.xenia.draw

import pl.jug.torun.xenia.meetup.Member
import spock.lang.Specification

class SkippedGiveAwayContainerSpec extends Specification {

def "should add skipped members for same giveaway"() {
given:
SkippedGiveAwayContainer container = new SkippedGiveAwayContainer()
Member firstMember = new Member(id: 100)
Member nextMember = new Member(id: 200)
GiveAway giveAway = new GiveAway(id: 1000)

when:
container.addSkippedMember(giveAway, firstMember)
container.addSkippedMember(giveAway, nextMember)

then:
container.getMembersByGiveAway(giveAway).with {
it.size() == 2 && it[0] == firstMember && it[1] == nextMember
}
}

def "should add skipped members for different giveaways"() {
given:
SkippedGiveAwayContainer container = new SkippedGiveAwayContainer()
Member firstMember = new Member(id: 100)
Member nextMember = new Member(id: 200)
GiveAway firstGiveAway = new GiveAway(id: 1000)
GiveAway nextGiveAway = new GiveAway(id: 2000)

when:
container.addSkippedMember(firstGiveAway, firstMember)
container.addSkippedMember(nextGiveAway, nextMember)

then:
container.getMembersByGiveAway(firstGiveAway).with {
it.size() == 1 && it[0] == firstMember
}
container.getMembersByGiveAway(nextGiveAway).with {
it.size() == 1 && it[0] == nextMember
}
}

}