Skip to content

Commit f332b99

Browse files
authored
Merge pull request #5 from trendyol-data-eng-summer-intern-2019/dev
Dev
2 parents 9492b9f + 60f8191 commit f332b99

File tree

10 files changed

+103
-20
lines changed

10 files changed

+103
-20
lines changed

pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<groupId>com.trendyol</groupId>
1212
<artifactId>recom-engine-web-service</artifactId>
1313
<version>0.0.1-SNAPSHOT</version>
14-
<name>recom-engine</name>
14+
<name>recom-engine-web-service</name>
1515
<description>Demo project for Spring Boot</description>
1616

1717
<properties>
@@ -42,6 +42,12 @@
4242
<groupId>org.springframework.boot</groupId>
4343
<artifactId>spring-boot-starter-data-mongodb</artifactId>
4444
</dependency>
45+
<dependency>
46+
<groupId>org.testcontainers</groupId>
47+
<artifactId>testcontainers</artifactId>
48+
<version>1.11.3</version>
49+
<scope>test</scope>
50+
</dependency>
4551
</dependencies>
4652

4753
<build>

src/main/java/com/trendyol/recomengine/webservice/controller/ReviewController.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.springframework.web.bind.annotation.RestController;
1010

1111
import javax.validation.Valid;
12+
import javax.validation.constraints.NotBlank;
13+
import javax.validation.constraints.Pattern;
1214

1315
/**
1416
* Handles POST requests that contain user reviews, validates the data that comes from requests and sends them to Kafka.
@@ -33,7 +35,13 @@ public class ReviewController {
3335
* @see ReviewWithoutUserId
3436
*/
3537
@PostMapping(value = "/users/{userId}/reviews")
36-
public Object createReview(@Valid @RequestBody ReviewWithoutUserId requestBody, @PathVariable String userId) {
38+
public Object createReview(@Valid @RequestBody ReviewWithoutUserId requestBody,
39+
@PathVariable
40+
@Valid
41+
@NotBlank
42+
@Pattern(regexp = "^[a-zA-Z0-9]+$"
43+
, message = "userId must only contain alphanumeric characters.")
44+
String userId) {
3745
Review review = new Review(userId, requestBody);
3846

3947
String dataToSendToKafka = String.format("%s,%s,%.1f,%d", userId, requestBody.getProductId(),

src/main/java/com/trendyol/recomengine/webservice/model/Review.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.trendyol.recomengine.webservice.model;
22

33
import javax.validation.constraints.NotBlank;
4+
import javax.validation.constraints.Pattern;
45
import java.sql.Timestamp;
56

67
/**
@@ -9,6 +10,7 @@
910
public class Review extends ReviewWithoutUserId {
1011

1112
@NotBlank
13+
@Pattern(regexp = "^[a-zA-Z0-9]+$", message = "userId must only contain alphanumeric characters.")
1214
private final String userId;
1315

1416
/**

src/main/java/com/trendyol/recomengine/webservice/model/ReviewWithoutUserId.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.trendyol.recomengine.webservice.model;
22

3-
import javax.validation.constraints.DecimalMin;
4-
import javax.validation.constraints.Max;
5-
import javax.validation.constraints.NotBlank;
6-
import javax.validation.constraints.NotNull;
3+
import javax.validation.constraints.*;
74
import java.sql.Timestamp;
85

96
/**
@@ -12,6 +9,7 @@
129
public class ReviewWithoutUserId {
1310

1411
@NotBlank
12+
@Pattern(regexp = "^[a-zA-Z0-9]+$", message = "productId must only contain alphanumeric characters.")
1513
private final String productId;
1614

1715
@DecimalMin(value = "0.5")

src/main/java/com/trendyol/recomengine/webservice/repository/RecommendationRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import com.trendyol.recomengine.webservice.model.Recommendation;
44
import org.springframework.data.mongodb.repository.MongoRepository;
5+
import org.springframework.stereotype.Repository;
56

67
/**
78
* Used to fetch recommendations of a specific user from MongoDB. Extends interface MongoRepository that is needed to
89
* configure the Spring Boot application to retrieve data from MongoDB. Required confifgurations are made in the
910
* application.yml file.
1011
*/
12+
@Repository
1113
public interface RecommendationRepository extends MongoRepository<Recommendation, String> {
1214

1315
/**

src/main/resources/application.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ server:
33
spring:
44
data:
55
mongodb:
6-
host: localhost
6+
host: mongo1
77
port: 27017
88
database: recom-engine
99
kafka:
1010
template:
1111
default-topic: reviews
1212
producer:
13-
bootstrap-servers: localhost:9092
13+
bootstrap-servers: kafka1:19092
1414
key-serializer: org.apache.kafka.common.serialization.StringSerializer
1515
value-serializer: org.apache.kafka.common.serialization.StringSerializer
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.trendyol.recomengine.webservice.controller;
2+
3+
import org.junit.runner.RunWith;
4+
import org.springframework.boot.test.context.SpringBootTest;
5+
import org.springframework.boot.test.util.TestPropertyValues;
6+
import org.springframework.context.ApplicationContextInitializer;
7+
import org.springframework.context.ConfigurableApplicationContext;
8+
import org.springframework.context.event.ContextClosedEvent;
9+
import org.springframework.test.context.ActiveProfiles;
10+
import org.springframework.test.context.ContextConfiguration;
11+
import org.springframework.test.context.junit4.SpringRunner;
12+
import org.testcontainers.containers.GenericContainer;
13+
import org.testcontainers.containers.wait.strategy.Wait;
14+
15+
@RunWith(SpringRunner.class)
16+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
17+
@ActiveProfiles("test")
18+
@ContextConfiguration(initializers = BaseMongoIntegrationTest.Initializer.class)
19+
public abstract class BaseMongoIntegrationTest {
20+
private static final int MONGO_PORT = 27017;
21+
22+
private static GenericContainer mongoContainer = new GenericContainer("mongo:latest")
23+
.withExposedPorts(MONGO_PORT)
24+
.waitingFor(Wait.forListeningPort());
25+
26+
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
27+
@Override
28+
public void initialize(ConfigurableApplicationContext applicationContext) {
29+
mongoContainer.start();
30+
31+
TestPropertyValues.of("spring.data.mongodb.uri=mongodb://localhost:" + mongoContainer.getMappedPort(MONGO_PORT))
32+
.applyTo(applicationContext);
33+
34+
applicationContext.addApplicationListener(
35+
applicationEvent -> {
36+
if (applicationEvent instanceof ContextClosedEvent) {
37+
mongoContainer.stop();
38+
}
39+
}
40+
);
41+
}
42+
}
43+
}
44+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.trendyol.recomengine.webservice.controller;
2+
3+
import com.trendyol.recomengine.webservice.model.Recommendation;
4+
import com.trendyol.recomengine.webservice.repository.RecommendationRepository;
5+
import com.trendyol.recomengine.webservice.service.RecommendationService;
6+
import org.junit.Assert;
7+
import org.junit.Test;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
10+
public class RecommendationControllerIntegrationTests extends BaseMongoIntegrationTest {
11+
@Autowired
12+
private RecommendationRepository recommendationRepository;
13+
@Autowired
14+
private RecommendationService recommendationService;
15+
16+
@Test
17+
public void getRecommendationShouldReturnTheRelevantUsersRecommendation() {
18+
String userId = "3";
19+
String[] recommendations = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
20+
21+
Recommendation recommendation = new Recommendation(userId, recommendations);
22+
recommendationRepository.save(recommendation);
23+
Assert.assertEquals(recommendationService.getRecommendations(userId).get_id(), userId);
24+
}
25+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
@RunWith(SpringRunner.class)
2323
@SpringBootTest
2424
@AutoConfigureMockMvc
25-
public class RecommendationControllerTests {
25+
public class RecommendationControllerUnitTests {
2626

2727
@Autowired
2828
private MockMvc mockMvc;

src/test/java/com/trendyol/recomengine/webservice/controller/ReviewControllerTests.java renamed to src/test/java/com/trendyol/recomengine/webservice/controller/ReviewControllerUnitTests.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@
1313
import org.springframework.test.context.junit4.SpringRunner;
1414
import org.springframework.test.web.servlet.MockMvc;
1515

16-
import java.io.Serializable;
1716
import java.sql.Timestamp;
1817
import java.text.SimpleDateFormat;
1918
import java.util.TimeZone;
2019

21-
import static org.mockito.BDDMockito.given;
2220
import static org.springframework.test.web.servlet.ResultMatcher.matchAll;
2321
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
2422
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
@@ -27,14 +25,22 @@
2725
@RunWith(SpringRunner.class)
2826
@SpringBootTest
2927
@AutoConfigureMockMvc
30-
public class ReviewControllerTests {
28+
public class ReviewControllerUnitTests {
3129

3230
@Autowired
3331
private MockMvc mockMvc;
3432

3533
@MockBean
3634
private KafkaTemplate<String, String> kafkaTemplate;
3735

36+
public static String asJsonString(final Object obj) {
37+
try {
38+
return new ObjectMapper().writeValueAsString(obj);
39+
} catch (Exception e) {
40+
throw new RuntimeException(e);
41+
}
42+
}
43+
3844
@Test
3945
public void createReviewShouldReturnTheGivenReviewBack() throws Exception {
4046
String userId = "3";
@@ -101,14 +107,6 @@ public void createReviewShouldReturnBadRequestSinceAllFieldsDoNotExist() throws
101107
.andExpect(status().isBadRequest());
102108
}
103109

104-
public static String asJsonString(final Object obj) {
105-
try {
106-
return new ObjectMapper().writeValueAsString(obj);
107-
} catch (Exception e) {
108-
throw new RuntimeException(e);
109-
}
110-
}
111-
112110
private String getTimeStringFormatted(Timestamp time) {
113111
String timeStringFormatted;
114112
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

0 commit comments

Comments
 (0)