Skip to content

Commit 9f2727e

Browse files
committed
Purge unactivated registration requests each 12 hours.
Fixed #24
1 parent ffe7271 commit 9f2727e

File tree

5 files changed

+223
-1
lines changed

5 files changed

+223
-1
lines changed

src/main/java/ru/mystamps/web/config/MvcConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.context.annotation.Configuration;
2424
import org.springframework.context.MessageSource;
2525
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
26+
import org.springframework.scheduling.annotation.EnableScheduling;
2627
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
2728
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
2829
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@@ -39,6 +40,7 @@
3940

4041
@Configuration
4142
@EnableWebMvc
43+
@EnableScheduling
4244
@ComponentScan(basePackages = {
4345
"ru.mystamps.web.controller",
4446
"ru.mystamps.web.service"

src/main/java/ru/mystamps/web/dao/UsersActivationDao.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@
1818

1919
package ru.mystamps.web.dao;
2020

21+
import java.util.Date;
22+
import java.util.List;
23+
2124
import org.springframework.data.repository.CrudRepository;
2225

2326
import ru.mystamps.web.entity.UsersActivation;
2427

2528
public interface UsersActivationDao extends CrudRepository<UsersActivation, Integer> {
2629
UsersActivation findByActivationKey(final String activationKey);
30+
List<UsersActivation> findByCreatedAtLessThan(final Date expiredSince);
2731
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (C) 2012 Slava Semushin <slava.semushin@gmail.com>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
package ru.mystamps.web.service;
20+
21+
import java.util.Date;
22+
import java.util.List;
23+
24+
import javax.inject.Inject;
25+
26+
import org.apache.commons.lang3.time.DateUtils;
27+
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
30+
31+
import org.springframework.scheduling.annotation.Scheduled;
32+
import org.springframework.stereotype.Service;
33+
import org.springframework.transaction.annotation.Transactional;
34+
35+
import static com.google.common.base.Preconditions.checkState;
36+
37+
import ru.mystamps.web.dao.UsersActivationDao;
38+
import ru.mystamps.web.entity.UsersActivation;
39+
40+
@Service
41+
public class CronService {
42+
43+
public static final int PURGE_UNACTIVATED_REQUEST_AFTER_DAYS = 3;
44+
45+
private static final long CHECK_UNACTIVATED_REQUESTS_PERIOD = 12 * DateUtils.MILLIS_PER_HOUR;
46+
47+
private final Logger log = LoggerFactory.getLogger(CronService.class);
48+
49+
@Inject
50+
private UsersActivationDao usersActivationDao;
51+
52+
@Scheduled(fixedDelay = CHECK_UNACTIVATED_REQUESTS_PERIOD)
53+
@Transactional
54+
public void purgeUsersActivations() {
55+
final Date expiredSince = DateUtils.addDays(
56+
new Date(),
57+
-PURGE_UNACTIVATED_REQUEST_AFTER_DAYS
58+
);
59+
60+
final List<UsersActivation> expiredActivations =
61+
usersActivationDao.findByCreatedAtLessThan(expiredSince);
62+
63+
checkState(expiredActivations != null, "Expired activations should be non null");
64+
65+
if (expiredActivations.isEmpty()) {
66+
log.info("Expired activations was not found.");
67+
return;
68+
}
69+
70+
for (final UsersActivation activation : expiredActivations) {
71+
log.info(
72+
"Delete expired activation (key: {}, email: {}, created: {})",
73+
new Object[] {
74+
activation.getActivationKey(),
75+
activation.getEmail(),
76+
activation.getCreatedAt()
77+
}
78+
);
79+
}
80+
81+
usersActivationDao.delete(expiredActivations);
82+
}
83+
84+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright (C) 2012 Slava Semushin <slava.semushin@gmail.com>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
package ru.mystamps.web.service;
20+
21+
import java.util.Calendar;
22+
import java.util.Collections;
23+
import java.util.Date;
24+
import java.util.GregorianCalendar;
25+
import java.util.List;
26+
27+
import org.apache.commons.lang3.time.DateUtils;
28+
29+
import org.testng.annotations.BeforeMethod;
30+
import org.testng.annotations.Test;
31+
32+
import org.mockito.ArgumentCaptor;
33+
import org.mockito.Captor;
34+
import org.mockito.InjectMocks;
35+
import org.mockito.Mock;
36+
import org.mockito.MockitoAnnotations;
37+
38+
import static org.fest.assertions.Assertions.assertThat;
39+
40+
import static org.mockito.Mockito.any;
41+
import static org.mockito.Mockito.eq;
42+
import static org.mockito.Mockito.never;
43+
import static org.mockito.Mockito.verify;
44+
import static org.mockito.Mockito.when;
45+
46+
import ru.mystamps.web.dao.UsersActivationDao;
47+
import ru.mystamps.web.entity.UsersActivation;
48+
49+
public class CronServiceTest {
50+
51+
@Mock
52+
private UsersActivationDao usersActivationDao;
53+
54+
@Captor
55+
private ArgumentCaptor<Date> dateCaptor;
56+
57+
@InjectMocks
58+
private CronService service = new CronService();
59+
60+
@BeforeMethod
61+
public void setUp() {
62+
MockitoAnnotations.initMocks(this);
63+
}
64+
65+
//
66+
// Tests for purgeUsersActivations()
67+
//
68+
69+
@Test
70+
public void purgeUsersActivationsShouldGetExpiredActivationsFromDao() {
71+
when(usersActivationDao.findByCreatedAtLessThan(any(Date.class)))
72+
.thenReturn(Collections.<UsersActivation>emptyList());
73+
74+
service.purgeUsersActivations();
75+
76+
verify(usersActivationDao).findByCreatedAtLessThan(any(Date.class));
77+
}
78+
79+
@Test
80+
public void purgeUsersActivationsShouldPassExpiredDateToDao() {
81+
when(usersActivationDao.findByCreatedAtLessThan(any(Date.class)))
82+
.thenReturn(Collections.<UsersActivation>emptyList());
83+
84+
service.purgeUsersActivations();
85+
86+
verify(usersActivationDao).findByCreatedAtLessThan(dateCaptor.capture());
87+
88+
final Calendar calendar = new GregorianCalendar().getInstance();
89+
calendar.setTime(new Date());
90+
calendar.add(
91+
Calendar.DAY_OF_MONTH,
92+
-(CronService.PURGE_UNACTIVATED_REQUEST_AFTER_DAYS)
93+
);
94+
95+
// Truncate seconds in dates to prevent test fail due to different milliseconds in dates
96+
final Date expectedDate = DateUtils.truncate(calendar.getTime(), Calendar.SECOND);
97+
final Date passedDate = DateUtils.truncate(dateCaptor.getValue(), Calendar.SECOND);
98+
99+
assertThat(passedDate.equals(expectedDate)).isTrue();
100+
}
101+
102+
@Test(expectedExceptions = IllegalStateException.class)
103+
public void purgeUsersActivationsShouldThrowExceptionWhenNullActivationsWasReturned() {
104+
when(usersActivationDao.findByCreatedAtLessThan(any(Date.class))).thenReturn(null);
105+
106+
service.purgeUsersActivations();
107+
}
108+
109+
@Test
110+
public void purgeUsersActivationsShouldDeleteExpiredActivations() {
111+
final List<UsersActivation> expectedActivations =
112+
Collections.singletonList(UserServiceTest.getUsersActivation());
113+
when(usersActivationDao.findByCreatedAtLessThan(any(Date.class)))
114+
.thenReturn(expectedActivations);
115+
116+
service.purgeUsersActivations();
117+
118+
verify(usersActivationDao).delete(eq(expectedActivations));
119+
}
120+
121+
@Test
122+
public void purgeUsersActivationsShouldDoNothingIfNoActivations() {
123+
when(usersActivationDao.findByCreatedAtLessThan(any(Date.class)))
124+
.thenReturn(Collections.<UsersActivation>emptyList());
125+
126+
service.purgeUsersActivations();
127+
128+
verify(usersActivationDao, never()).delete(any(Iterable.class));
129+
}
130+
131+
}
132+

src/test/java/ru/mystamps/web/service/UserServiceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ private User getValidUser() {
446446
return user;
447447
}
448448

449-
private UsersActivation getUsersActivation() {
449+
static UsersActivation getUsersActivation() {
450450
final UsersActivation activation = new UsersActivation();
451451
activation.setActivationKey(TEST_ACTIVATION_KEY);
452452
activation.setEmail(TEST_EMAIL);

0 commit comments

Comments
 (0)