Skip to content
This repository was archived by the owner on Apr 12, 2020. It is now read-only.

Commit 9dc221e

Browse files
committed
added cron job for deleting expired secrets. fix #2
1 parent 5e548d0 commit 9dc221e

File tree

7 files changed

+99
-5
lines changed

7 files changed

+99
-5
lines changed

pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@
8787
<version>0.11</version>
8888
<scope>test</scope>
8989
</dependency>
90+
<dependency>
91+
<groupId>org.awaitility</groupId>
92+
<artifactId>awaitility</artifactId>
93+
<version>3.1.6</version>
94+
<scope>test</scope>
95+
</dependency>
9096
<!--<dependency>
9197
<groupId>org.springframework.security</groupId>
9298
<artifactId>spring-security-test</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2019 Isaak Malik <[email protected]>
3+
*
4+
* Licensed as open source under the EUROPEAN UNION PUBLIC LICENCE v. 1.2
5+
* See LICENSE, LICENTIE or for other translations: https://joinup.ec.europa.eu/collection/eupl/eupl-text-11-12
6+
*/
7+
8+
package click.wheredoi.secretshareapi;
9+
10+
import click.wheredoi.secretshareapi.service.SecretService;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
import org.springframework.scheduling.annotation.Scheduled;
14+
import org.springframework.stereotype.Component;
15+
16+
@Component
17+
public class ScheduledTasks {
18+
private final Logger logger = LoggerFactory.getLogger(getClass());
19+
20+
private final SecretService secretService;
21+
22+
public ScheduledTasks(SecretService secretService) {
23+
this.secretService = secretService;
24+
}
25+
26+
// Each hour
27+
@Scheduled(cron = "0 0 * * * *")
28+
public void cronDeleteExpiredSecrets() {
29+
secretService.deleteExpiredSecrets();
30+
logger.info("Cron job cronDeleteExpiredSecrets() has been executed");
31+
}
32+
}

src/main/java/click/wheredoi/secretshareapi/SecretshareapiApplication.java

+2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import org.springframework.boot.SpringApplication;
1313
import org.springframework.boot.autoconfigure.SpringBootApplication;
1414
import org.springframework.context.annotation.Bean;
15+
import org.springframework.scheduling.annotation.EnableScheduling;
1516

1617
@SpringBootApplication
18+
@EnableScheduling
1719
public class SecretshareapiApplication {
1820

1921
public static void main(String[] args) {

src/main/java/click/wheredoi/secretshareapi/service/SecretService.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import click.wheredoi.secretshareapi.model.Secret;
1313
import click.wheredoi.secretshareapi.repo.SecretRepository;
1414
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
1517
import org.springframework.stereotype.Service;
1618

1719
import javax.servlet.http.HttpServletRequest;
@@ -21,9 +23,8 @@
2123

2224
@Service
2325
public class SecretService {
24-
26+
private final Logger logger = LoggerFactory.getLogger(getClass());
2527
private final SecretRepository secretRepository;
26-
2728
private final AccessService accessService;
2829

2930
public SecretService(SecretRepository secretRepository, AccessService accessService) {
@@ -69,10 +70,12 @@ public Secret getSecret(String id, HttpServletRequest request) {
6970
}
7071

7172
/**
72-
* Delete expired, should be triggered by a cron job or so
73-
* TODO: implement automation
73+
* Delete expired, is automatically executed by cronDeleteExpiredSecrets()
74+
*
75+
* @see click.wheredoi.secretshareapi.ScheduledTasks
7476
*/
7577
public void deleteExpiredSecrets() {
7678
secretRepository.deleteExpired();
79+
logger.info("deleteExpiredSecrets(): expired secrets have been deleted");
7780
}
7881
}

src/main/resources/application.properties

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ spring.jpa.properties.javax.persistence.validation.mode=none
1818
spring.jackson.serialization.indent_output=true
1919
spring.servlet.multipart.max-request-size=5MB
2020
logging.level.click.wheredoi=warn
21+
logging.file=secretshare.log
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2019 Isaak Malik <[email protected]>
3+
*
4+
* Licensed as open source under the EUROPEAN UNION PUBLIC LICENCE v. 1.2
5+
* See LICENSE, LICENTIE or for other translations: https://joinup.ec.europa.eu/collection/eupl/eupl-text-11-12
6+
*/
7+
8+
package click.wheredoi.secretshareapi;
9+
10+
import click.wheredoi.secretshareapi.service.SecretService;
11+
import org.awaitility.Duration;
12+
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Disabled;
14+
import org.junit.jupiter.api.Test;
15+
import org.mockito.Mock;
16+
import org.mockito.Mockito;
17+
import org.mockito.MockitoAnnotations;
18+
19+
import static org.awaitility.Awaitility.await;
20+
import static org.mockito.Mockito.atLeast;
21+
import static org.mockito.Mockito.verify;
22+
23+
// Disabled because not possible to test the one hour cron job immediately
24+
@Disabled
25+
class ScheduledTasksTest {
26+
@Mock
27+
private ScheduledTasks tasks;
28+
29+
@Mock
30+
private SecretService secretService;
31+
32+
@BeforeEach
33+
void setup() {
34+
MockitoAnnotations.initMocks(this);
35+
}
36+
37+
@Test
38+
void testCronDeleteExpiredSecrets() {
39+
Mockito.doNothing().when(secretService).deleteExpiredSecrets();
40+
41+
await().atMost(Duration.FIVE_SECONDS).untilAsserted(() ->
42+
verify(tasks, atLeast(1)).cronDeleteExpiredSecrets());
43+
}
44+
}

src/test/java/click/wheredoi/secretshareapi/controller/IndexControllerTest.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import javax.servlet.http.HttpServletRequest;
2828
import java.sql.Timestamp;
29+
import java.util.ArrayList;
2930
import java.util.HashSet;
3031
import java.util.Random;
3132
import java.util.Set;
@@ -73,6 +74,7 @@ void setUp() {
7374
accessRecord.setIp("127.0.0.1");
7475
accessRecord.setId(1);
7576
accessRecord.setSecret(secret.getId());
77+
accessRecord.setTime(new Timestamp(System.currentTimeMillis()));
7678
Set<AccessRecord> accessRecords = new HashSet<>();
7779
accessRecords.add(accessRecord);
7880
secret.setAccessRecords(accessRecords);
@@ -127,13 +129,17 @@ void createSecretReturnsSecret() throws Exception {
127129
@Test
128130
void getSecretShouldReturnSecretAndAccessRecords() throws Exception {
129131
Mockito.when(secretService.getSecret(Mockito.eq(nanoId), Mockito.any(HttpServletRequest.class))).thenReturn(secret);
132+
AccessRecord accessRecord = new ArrayList<>(secret.getAccessRecords()).get(0);
130133

131134
mockMvc.perform(get("/" + nanoId).contentType(MediaType.APPLICATION_JSON))
132135
.andExpect(status().isOk())
133136
.andExpect(jsonPath("$.id", equalTo(nanoId)))
134137
.andExpect(jsonPath("$.data", equalTo(secret.getData())))
135138
.andExpect(jsonPath("$.expires", equalTo(secret.getExpires().getTime())))
136-
.andExpect(jsonPath("$.accessRecords[0].secret", equalTo(secret.getId())));
139+
.andExpect(jsonPath("$.accessRecords[0].secret").doesNotExist())
140+
.andExpect(jsonPath("$.accessRecords[0].id").doesNotExist())
141+
.andExpect(jsonPath("$.accessRecords[0].ip").value(accessRecord.getIp()))
142+
.andExpect(jsonPath("$.accessRecords[0].time").value(accessRecord.getTime().getTime()));
137143
}
138144

139145
@Test

0 commit comments

Comments
 (0)