From b0a3fd1a120afb5c19f2c83b98725ec63acecde6 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 24 Apr 2024 16:27:32 +0700 Subject: [PATCH 01/20] [REFACTOR] Add Spring Boot JPA and PostgreSQL dependencies, and update Review model and ReviewState classes --- build.gradle.kts | 2 ++ .../snackscription/review/model/Review.java | 26 ++++++++++++++++--- .../review/model/ReviewState.java | 21 ++++++++++++++- .../review/model/ReviewStateApproved.java | 6 +---- .../review/model/ReviewStatePending.java | 6 +---- .../review/model/ReviewStateRejected.java | 7 ++--- .../review/model/ReviewTest.java | 9 ++----- 7 files changed, 51 insertions(+), 26 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2a83950..c18a996 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,10 +23,12 @@ repositories { } dependencies { + implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.springframework.boot:spring-boot-starter-web") compileOnly("org.projectlombok:lombok") developmentOnly("org.springframework.boot:spring-boot-devtools") + runtimeOnly("org.postgresql:postgresql") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") annotationProcessor("org.projectlombok:lombok") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/src/main/java/snackscription/review/model/Review.java b/src/main/java/snackscription/review/model/Review.java index c05c8b9..f8b2dd4 100644 --- a/src/main/java/snackscription/review/model/Review.java +++ b/src/main/java/snackscription/review/model/Review.java @@ -4,17 +4,36 @@ import lombok.Setter; import java.util.UUID; +import jakarta.persistence.*; + @Getter +@Entity +@Table(name = "review") public class Review { - private final String id; + @Id + private String id; + + @Column(name = "rating", nullable = false) private int rating; + @Setter + @Column(name = "content", nullable = false) private String content; + @Setter + @ManyToOne + @JoinColumn(name = "state_id", nullable = false) private ReviewState state; - private final String userId; - private final String subscriptionBoxId; + + @Column(name="user_id", nullable = false) + private String userId; + + @Column(name="subsbox_id", nullable = false) + private String subscriptionBoxId; + + public Review() { + } public Review(int rating, String content, String userId, String subscriptionBoxId) { this.id = UUID.randomUUID().toString(); @@ -25,6 +44,7 @@ public Review(int rating, String content, String userId, String subscriptionBoxI this.subscriptionBoxId = subscriptionBoxId; } + public void editReview(int rating, String content) { this.setRating(rating); this.setContent(content); diff --git a/src/main/java/snackscription/review/model/ReviewState.java b/src/main/java/snackscription/review/model/ReviewState.java index b6d5daa..554491d 100644 --- a/src/main/java/snackscription/review/model/ReviewState.java +++ b/src/main/java/snackscription/review/model/ReviewState.java @@ -1,8 +1,22 @@ package snackscription.review.model; +import jakarta.persistence.*; + + +@Entity +@Table(name = "review_state") public abstract class ReviewState { + + @Transient Review review; - String state; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + + @Column(nullable = false) + String name; + ReviewState(Review review) { this.review = review; } @@ -10,4 +24,9 @@ public abstract class ReviewState { public abstract void approve(); public abstract void reject(); + + @Override + public String toString() { + return this.name; + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateApproved.java b/src/main/java/snackscription/review/model/ReviewStateApproved.java index 3875665..43d67ed 100644 --- a/src/main/java/snackscription/review/model/ReviewStateApproved.java +++ b/src/main/java/snackscription/review/model/ReviewStateApproved.java @@ -4,6 +4,7 @@ public class ReviewStateApproved extends ReviewState { ReviewStateApproved(Review review) { super(review); + this.name = "Approved"; } @Override @@ -15,9 +16,4 @@ public void approve() { public void reject() { this.review.setState(new ReviewStateRejected(this.review)); } - - @Override - public String toString() { - return "Approved"; - } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStatePending.java b/src/main/java/snackscription/review/model/ReviewStatePending.java index 0064775..efcb1f5 100644 --- a/src/main/java/snackscription/review/model/ReviewStatePending.java +++ b/src/main/java/snackscription/review/model/ReviewStatePending.java @@ -4,6 +4,7 @@ public class ReviewStatePending extends ReviewState { ReviewStatePending(Review review) { super(review); + this.name = "Pending"; } @Override @@ -15,9 +16,4 @@ public void approve() { public void reject() { this.review.setState(new ReviewStateRejected(this.review)); } - - @Override - public String toString() { - return "Pending"; - } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateRejected.java b/src/main/java/snackscription/review/model/ReviewStateRejected.java index 68df2cd..90fa050 100644 --- a/src/main/java/snackscription/review/model/ReviewStateRejected.java +++ b/src/main/java/snackscription/review/model/ReviewStateRejected.java @@ -1,8 +1,10 @@ package snackscription.review.model; public class ReviewStateRejected extends ReviewState { + ReviewStateRejected(Review review) { super(review); + this.name = "Rejected"; } @Override @@ -14,9 +16,4 @@ public void approve() { public void reject() { throw new RuntimeException("Review already rejected."); } - - @Override - public String toString() { - return "Rejected"; - } } \ No newline at end of file diff --git a/src/test/java/snackscription/review/model/ReviewTest.java b/src/test/java/snackscription/review/model/ReviewTest.java index 74815f8..c68085d 100644 --- a/src/test/java/snackscription/review/model/ReviewTest.java +++ b/src/test/java/snackscription/review/model/ReviewTest.java @@ -10,16 +10,11 @@ public class ReviewTest { @BeforeEach void setUp() { - this.review = new Review( - 5, - "Bagus bgt dah", - "1", - "111" - ); + this.review = new Review(5, "Great product!", "user1", "subsbox1"); } @Test - void testCreateReview() { + void testConstructor() { int rating = 3; String content = "Wow!"; String userId = "33"; From 5427ada7b4ac727e562e6e6bd2a0171429e70bda Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 24 Apr 2024 20:18:44 +0700 Subject: [PATCH 02/20] Revert "[REFACTOR] Add Spring Boot JPA and PostgreSQL dependencies, and update Review model and ReviewState classes" This reverts commit b0a3fd1a120afb5c19f2c83b98725ec63acecde6. --- build.gradle.kts | 2 -- .../snackscription/review/model/Review.java | 26 +++---------------- .../review/model/ReviewState.java | 21 +-------------- .../review/model/ReviewStateApproved.java | 6 ++++- .../review/model/ReviewStatePending.java | 6 ++++- .../review/model/ReviewStateRejected.java | 7 +++-- .../review/model/ReviewTest.java | 9 +++++-- 7 files changed, 26 insertions(+), 51 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index c18a996..2a83950 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,12 +23,10 @@ repositories { } dependencies { - implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.springframework.boot:spring-boot-starter-web") compileOnly("org.projectlombok:lombok") developmentOnly("org.springframework.boot:spring-boot-devtools") - runtimeOnly("org.postgresql:postgresql") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") annotationProcessor("org.projectlombok:lombok") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/src/main/java/snackscription/review/model/Review.java b/src/main/java/snackscription/review/model/Review.java index f8b2dd4..c05c8b9 100644 --- a/src/main/java/snackscription/review/model/Review.java +++ b/src/main/java/snackscription/review/model/Review.java @@ -4,36 +4,17 @@ import lombok.Setter; import java.util.UUID; -import jakarta.persistence.*; - @Getter -@Entity -@Table(name = "review") public class Review { - @Id - private String id; - - @Column(name = "rating", nullable = false) + private final String id; private int rating; - @Setter - @Column(name = "content", nullable = false) private String content; - @Setter - @ManyToOne - @JoinColumn(name = "state_id", nullable = false) private ReviewState state; - - @Column(name="user_id", nullable = false) - private String userId; - - @Column(name="subsbox_id", nullable = false) - private String subscriptionBoxId; - - public Review() { - } + private final String userId; + private final String subscriptionBoxId; public Review(int rating, String content, String userId, String subscriptionBoxId) { this.id = UUID.randomUUID().toString(); @@ -44,7 +25,6 @@ public Review(int rating, String content, String userId, String subscriptionBoxI this.subscriptionBoxId = subscriptionBoxId; } - public void editReview(int rating, String content) { this.setRating(rating); this.setContent(content); diff --git a/src/main/java/snackscription/review/model/ReviewState.java b/src/main/java/snackscription/review/model/ReviewState.java index 554491d..b6d5daa 100644 --- a/src/main/java/snackscription/review/model/ReviewState.java +++ b/src/main/java/snackscription/review/model/ReviewState.java @@ -1,22 +1,8 @@ package snackscription.review.model; -import jakarta.persistence.*; - - -@Entity -@Table(name = "review_state") public abstract class ReviewState { - - @Transient Review review; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - Long id; - - @Column(nullable = false) - String name; - + String state; ReviewState(Review review) { this.review = review; } @@ -24,9 +10,4 @@ public abstract class ReviewState { public abstract void approve(); public abstract void reject(); - - @Override - public String toString() { - return this.name; - } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateApproved.java b/src/main/java/snackscription/review/model/ReviewStateApproved.java index 43d67ed..3875665 100644 --- a/src/main/java/snackscription/review/model/ReviewStateApproved.java +++ b/src/main/java/snackscription/review/model/ReviewStateApproved.java @@ -4,7 +4,6 @@ public class ReviewStateApproved extends ReviewState { ReviewStateApproved(Review review) { super(review); - this.name = "Approved"; } @Override @@ -16,4 +15,9 @@ public void approve() { public void reject() { this.review.setState(new ReviewStateRejected(this.review)); } + + @Override + public String toString() { + return "Approved"; + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStatePending.java b/src/main/java/snackscription/review/model/ReviewStatePending.java index efcb1f5..0064775 100644 --- a/src/main/java/snackscription/review/model/ReviewStatePending.java +++ b/src/main/java/snackscription/review/model/ReviewStatePending.java @@ -4,7 +4,6 @@ public class ReviewStatePending extends ReviewState { ReviewStatePending(Review review) { super(review); - this.name = "Pending"; } @Override @@ -16,4 +15,9 @@ public void approve() { public void reject() { this.review.setState(new ReviewStateRejected(this.review)); } + + @Override + public String toString() { + return "Pending"; + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateRejected.java b/src/main/java/snackscription/review/model/ReviewStateRejected.java index 90fa050..68df2cd 100644 --- a/src/main/java/snackscription/review/model/ReviewStateRejected.java +++ b/src/main/java/snackscription/review/model/ReviewStateRejected.java @@ -1,10 +1,8 @@ package snackscription.review.model; public class ReviewStateRejected extends ReviewState { - ReviewStateRejected(Review review) { super(review); - this.name = "Rejected"; } @Override @@ -16,4 +14,9 @@ public void approve() { public void reject() { throw new RuntimeException("Review already rejected."); } + + @Override + public String toString() { + return "Rejected"; + } } \ No newline at end of file diff --git a/src/test/java/snackscription/review/model/ReviewTest.java b/src/test/java/snackscription/review/model/ReviewTest.java index c68085d..74815f8 100644 --- a/src/test/java/snackscription/review/model/ReviewTest.java +++ b/src/test/java/snackscription/review/model/ReviewTest.java @@ -10,11 +10,16 @@ public class ReviewTest { @BeforeEach void setUp() { - this.review = new Review(5, "Great product!", "user1", "subsbox1"); + this.review = new Review( + 5, + "Bagus bgt dah", + "1", + "111" + ); } @Test - void testConstructor() { + void testCreateReview() { int rating = 3; String content = "Wow!"; String userId = "33"; From 6ec68aa7466df5af556a642391fd51004e9fb72b Mon Sep 17 00:00:00 2001 From: asteriskzie <76894331+asteriskzie@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:27:20 +0700 Subject: [PATCH 03/20] Configure database (#6) * Configure database * Debug appcliation-test.properties * Add PostgreSQL database connection in ci.yml workflow file * Update PostgreSQL port in ci.yml workflow file * Update PostgreSQL service configuration in ci.yml workflow file * Update PostgreSQL user and database name in ci.yml workflow file * Update PostgreSQL database creation in ci.yml workflow file * Update PostgreSQL service configuration and port in ci.yml workflow file Lot's of debugging :D --- .github/workflows/ci.yml | 16 +++++++++-- build.gradle.kts | 2 ++ .../review/controller/ReviewController.java | 17 +++++++++++- .../snackscription/review/model/Review.java | 27 ++++++++++++++++--- .../review/model/ReviewState.java | 25 ++++++++++++++++- .../review/model/ReviewStateApproved.java | 6 +---- .../review/model/ReviewStatePending.java | 6 +---- .../review/model/ReviewStateRejected.java | 7 ++--- .../review/repository/ReviewRepository.java | 6 +++++ src/main/resources/application-dev.properties | 2 +- .../resources/application-test.properties | 2 +- 11 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 src/main/java/snackscription/review/repository/ReviewRepository.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8fd178..6dbb8fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,9 +4,11 @@ on: push: branches: - main + - dev pull_request: branches: - main + - dev workflow_dispatch: jobs: @@ -42,12 +44,22 @@ jobs: uses: actions/upload-artifact@v4 with: name: java-app - path: build/libs/*.jar + path: build/libs/*.jar test: name: Test runs-on: ubuntu-latest - needs: build + needs: build + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: snackscription_review + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout Repository uses: actions/checkout@v4 diff --git a/build.gradle.kts b/build.gradle.kts index 2a83950..c18a996 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,10 +23,12 @@ repositories { } dependencies { + implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.springframework.boot:spring-boot-starter-web") compileOnly("org.projectlombok:lombok") developmentOnly("org.springframework.boot:spring-boot-devtools") + runtimeOnly("org.postgresql:postgresql") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") annotationProcessor("org.projectlombok:lombok") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/src/main/java/snackscription/review/controller/ReviewController.java b/src/main/java/snackscription/review/controller/ReviewController.java index 7abe48b..47b3b82 100644 --- a/src/main/java/snackscription/review/controller/ReviewController.java +++ b/src/main/java/snackscription/review/controller/ReviewController.java @@ -4,12 +4,27 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import snackscription.review.model.Review; +import snackscription.review.repository.ReviewRepository; -@Controller +@RestController @RequestMapping("/") public class ReviewController { + + private final ReviewRepository reviewRepository; + + public ReviewController(ReviewRepository reviewRepository) { + this.reviewRepository = reviewRepository; + } + @GetMapping("") public ResponseEntity reviewPage() { return ResponseEntity.ok().body("Welcome to the review service!"); } + + @GetMapping("/all") + public Iterable findAllReview() { + return this.reviewRepository.findAll(); + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/Review.java b/src/main/java/snackscription/review/model/Review.java index c05c8b9..5e737b5 100644 --- a/src/main/java/snackscription/review/model/Review.java +++ b/src/main/java/snackscription/review/model/Review.java @@ -4,17 +4,37 @@ import lombok.Setter; import java.util.UUID; +import jakarta.persistence.*; + @Getter +@Entity +@Table(name = "review") public class Review { - private final String id; + @Id + private String id; + + @Column(name = "rating", nullable = false) private int rating; + @Setter + @Column(name = "content", nullable = false) private String content; + +// @Transient @Setter + @ManyToOne + @JoinColumn(name = "state_id", nullable = false) private ReviewState state; - private final String userId; - private final String subscriptionBoxId; + + @Column(name="user_id", nullable = false) + private String userId; + + @Column(name="subsbox_id", nullable = false) + private String subscriptionBoxId; + + public Review() { + } public Review(int rating, String content, String userId, String subscriptionBoxId) { this.id = UUID.randomUUID().toString(); @@ -25,6 +45,7 @@ public Review(int rating, String content, String userId, String subscriptionBoxI this.subscriptionBoxId = subscriptionBoxId; } + public void editReview(int rating, String content) { this.setRating(rating); this.setContent(content); diff --git a/src/main/java/snackscription/review/model/ReviewState.java b/src/main/java/snackscription/review/model/ReviewState.java index b6d5daa..802a321 100644 --- a/src/main/java/snackscription/review/model/ReviewState.java +++ b/src/main/java/snackscription/review/model/ReviewState.java @@ -1,13 +1,36 @@ package snackscription.review.model; +import jakarta.persistence.*; + + +@Entity +@Table(name = "review_state") public abstract class ReviewState { + + @Transient Review review; - String state; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + Long id; + + @Column(nullable = false) + String name; + ReviewState(Review review) { this.review = review; } + public ReviewState() { + + } + public abstract void approve(); public abstract void reject(); + + @Override + public String toString() { + return this.name; + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateApproved.java b/src/main/java/snackscription/review/model/ReviewStateApproved.java index 3875665..43d67ed 100644 --- a/src/main/java/snackscription/review/model/ReviewStateApproved.java +++ b/src/main/java/snackscription/review/model/ReviewStateApproved.java @@ -4,6 +4,7 @@ public class ReviewStateApproved extends ReviewState { ReviewStateApproved(Review review) { super(review); + this.name = "Approved"; } @Override @@ -15,9 +16,4 @@ public void approve() { public void reject() { this.review.setState(new ReviewStateRejected(this.review)); } - - @Override - public String toString() { - return "Approved"; - } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStatePending.java b/src/main/java/snackscription/review/model/ReviewStatePending.java index 0064775..efcb1f5 100644 --- a/src/main/java/snackscription/review/model/ReviewStatePending.java +++ b/src/main/java/snackscription/review/model/ReviewStatePending.java @@ -4,6 +4,7 @@ public class ReviewStatePending extends ReviewState { ReviewStatePending(Review review) { super(review); + this.name = "Pending"; } @Override @@ -15,9 +16,4 @@ public void approve() { public void reject() { this.review.setState(new ReviewStateRejected(this.review)); } - - @Override - public String toString() { - return "Pending"; - } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateRejected.java b/src/main/java/snackscription/review/model/ReviewStateRejected.java index 68df2cd..90fa050 100644 --- a/src/main/java/snackscription/review/model/ReviewStateRejected.java +++ b/src/main/java/snackscription/review/model/ReviewStateRejected.java @@ -1,8 +1,10 @@ package snackscription.review.model; public class ReviewStateRejected extends ReviewState { + ReviewStateRejected(Review review) { super(review); + this.name = "Rejected"; } @Override @@ -14,9 +16,4 @@ public void approve() { public void reject() { throw new RuntimeException("Review already rejected."); } - - @Override - public String toString() { - return "Rejected"; - } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/repository/ReviewRepository.java b/src/main/java/snackscription/review/repository/ReviewRepository.java new file mode 100644 index 0000000..0d7b6ce --- /dev/null +++ b/src/main/java/snackscription/review/repository/ReviewRepository.java @@ -0,0 +1,6 @@ +package snackscription.review.repository; + +import org.springframework.data.repository.CrudRepository; +import snackscription.review.model.Review; + +public interface ReviewRepository extends CrudRepository {} \ No newline at end of file diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 4983766..dfdbb9f 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,4 +1,4 @@ -spring.datasource.url=jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/snackscription_review spring.datasource.username=postgres spring.datasource.password=postgres spring.jpa.hibernate.ddl-auto=create-drop diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 9b629dc..2a1ec97 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1,4 +1,4 @@ -spring.datasource.url=jdbc:postgresql://aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/snackscription_review spring.datasource.username=postgres spring.datasource.password=postgres spring.jpa.hibernate.ddl-auto=create From 8df727073bc0c96124f0735f431f962bea8d6764 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Thu, 25 Apr 2024 22:45:15 +0700 Subject: [PATCH 04/20] Exploratory coding for Controller-Service-Repository --- .../review/controller/ReviewController.java | 26 ++++-- .../review/exception/ControllerAdvisor.java | 18 ++++ .../exception/ReviewNotFoundException.java | 5 ++ .../snackscription/review/model/Review.java | 1 + .../review/service/ReviewService.java | 25 ++++++ .../controller/ReviewControllerTest.java | 80 ++++++++++++++++++ .../review/service/ReviewServiceTest.java | 83 +++++++++++++++++++ 7 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 src/main/java/snackscription/review/exception/ControllerAdvisor.java create mode 100644 src/main/java/snackscription/review/exception/ReviewNotFoundException.java create mode 100644 src/main/java/snackscription/review/service/ReviewService.java create mode 100644 src/test/java/snackscription/review/controller/ReviewControllerTest.java create mode 100644 src/test/java/snackscription/review/service/ReviewServiceTest.java diff --git a/src/main/java/snackscription/review/controller/ReviewController.java b/src/main/java/snackscription/review/controller/ReviewController.java index 47b3b82..f0921ca 100644 --- a/src/main/java/snackscription/review/controller/ReviewController.java +++ b/src/main/java/snackscription/review/controller/ReviewController.java @@ -1,21 +1,28 @@ package snackscription.review.controller; +import java.util.ArrayList; + import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import snackscription.review.model.Review; import snackscription.review.repository.ReviewRepository; +import snackscription.review.service.ReviewService; + +import org.springframework.web.bind.annotation.RequestParam; + @RestController @RequestMapping("/") public class ReviewController { - private final ReviewRepository reviewRepository; + private ReviewService reviewService; - public ReviewController(ReviewRepository reviewRepository) { - this.reviewRepository = reviewRepository; + public ReviewController(ReviewService reviewService) { + this.reviewService = reviewService; } @GetMapping("") @@ -23,8 +30,13 @@ public ResponseEntity reviewPage() { return ResponseEntity.ok().body("Welcome to the review service!"); } - @GetMapping("/all") - public Iterable findAllReview() { - return this.reviewRepository.findAll(); - } + // @GetMapping("/api/subscription-boxes/{subsboxId}") + // public ArrayList getAllSubscriptionBoxReview(@PathVariable String subsboxId) throws Exception { + // return reviewService.getAllSubscriptionBoxReview(subsboxId); + // } + + @GetMapping("/api/reviews/{reviewId}") + public Review getById(@PathVariable String reviewId) throws Exception { + return reviewService.findById(reviewId); + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/exception/ControllerAdvisor.java b/src/main/java/snackscription/review/exception/ControllerAdvisor.java new file mode 100644 index 0000000..41859f8 --- /dev/null +++ b/src/main/java/snackscription/review/exception/ControllerAdvisor.java @@ -0,0 +1,18 @@ +package snackscription.review.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import snackscription.review.model.Review; + +@ControllerAdvice +public class ControllerAdvisor extends ResponseEntityExceptionHandler { + @ExceptionHandler(ReviewNotFoundException.class) + public ResponseEntity handleReviewNotFound(ReviewNotFoundException exc, WebRequest req) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } +} diff --git a/src/main/java/snackscription/review/exception/ReviewNotFoundException.java b/src/main/java/snackscription/review/exception/ReviewNotFoundException.java new file mode 100644 index 0000000..55cc718 --- /dev/null +++ b/src/main/java/snackscription/review/exception/ReviewNotFoundException.java @@ -0,0 +1,5 @@ +package snackscription.review.exception; + +public class ReviewNotFoundException extends Exception { + +} diff --git a/src/main/java/snackscription/review/model/Review.java b/src/main/java/snackscription/review/model/Review.java index 5e737b5..db90fff 100644 --- a/src/main/java/snackscription/review/model/Review.java +++ b/src/main/java/snackscription/review/model/Review.java @@ -1,6 +1,7 @@ package snackscription.review.model; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.util.UUID; diff --git a/src/main/java/snackscription/review/service/ReviewService.java b/src/main/java/snackscription/review/service/ReviewService.java new file mode 100644 index 0000000..821e1f9 --- /dev/null +++ b/src/main/java/snackscription/review/service/ReviewService.java @@ -0,0 +1,25 @@ +package snackscription.review.service; + +import java.util.Optional; + +import snackscription.review.exception.ReviewNotFoundException; +import snackscription.review.model.Review; +import snackscription.review.repository.ReviewRepository; + +public class ReviewService { + private ReviewRepository reviewRepository; + + public ReviewService (ReviewRepository reviewRepository) { + this.reviewRepository = reviewRepository; + } + + public Review findById(String reviewId) throws ReviewNotFoundException { + Optional oReview = reviewRepository.findById(reviewId); + + if (oReview.isEmpty()) { + throw new ReviewNotFoundException(); + } + + return oReview.get(); + } +} diff --git a/src/test/java/snackscription/review/controller/ReviewControllerTest.java b/src/test/java/snackscription/review/controller/ReviewControllerTest.java new file mode 100644 index 0000000..602e464 --- /dev/null +++ b/src/test/java/snackscription/review/controller/ReviewControllerTest.java @@ -0,0 +1,80 @@ +package snackscription.review.controller; + +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.when; + +import snackscription.review.model.Review; +import snackscription.review.service.ReviewService; + +@ExtendWith(SpringExtension.class) +@WebMvcTest(ReviewController.class) +public class ReviewControllerTest { + @MockBean + ReviewService reviewService; + + @Autowired + MockMvc mockMvc; + + // @Test + // public void testGetAllSubscriptionBoxReview() { + // String subsboxId = "subsboxId"; + + // ArrayList reviews = new ArrayList<>(); + // reviews.add(new Review(5, "amazing", "user1", subsboxId)); + // reviews.add(new Review(4, "good", "user2", subsboxId)); + + // when(reviewService.testGetAllSubscriptionBoxReview(subsboxId)).thenReturn(reviews); + + // ResultActions result = mockMvc.perform(get("/api/subscription-boxes/{subsboxId}", subsboxId)) + // .andExpect(status().isOk()) + // .andExpect(jsonPath("$", hasSize(2))) + // .andExpect(jsonPath("$[0].rating", is(5))) + // .andExpect(jsonPath("$[0].content", is("amazing"))) + // .andExpect(jsonPath("$[0].userId", is("user1"))) + // .andExpect(jsonPath("$[0].subscriptionBoxId", is(subsboxId))) + // .andExpect(jsonPath("$[1].rating", is(4))) + // .andExpect(jsonPath("$[1].content", is("good"))) + // .andExpect(jsonPath("$[1].userId", is("user2"))) + // .andExpect(jsonPath("$[1].subscriptionBoxId", is(subsboxId))); + + // verify(reviewService).testGetAllSubscriptionBoxReview(subsboxId); + // } + + @Test + public void testGetById() throws Exception { + Review review = new Review( + 5, "amazing", "user1", "subsboxId" + ); + String reviewId = review.getId(); + + when(reviewService.findById(reviewId)).thenReturn(review); + + ResultActions result = mockMvc.perform(get("/api/reviews/{reviewId}", reviewId)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.rating", is(5))) + .andExpect(jsonPath("$.content", is("amazing"))) + .andExpect(jsonPath("$.userId", is("user1"))) + .andExpect(jsonPath("$.subscriptionBoxId", is("subsboxId"))); + + verify(reviewService).findById(reviewId); + } +} diff --git a/src/test/java/snackscription/review/service/ReviewServiceTest.java b/src/test/java/snackscription/review/service/ReviewServiceTest.java new file mode 100644 index 0000000..d1ee4e4 --- /dev/null +++ b/src/test/java/snackscription/review/service/ReviewServiceTest.java @@ -0,0 +1,83 @@ +package snackscription.review.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import javax.naming.spi.DirStateFactory.Result; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.ResultActions; + +import snackscription.review.exception.ReviewNotFoundException; +import snackscription.review.model.Review; +import snackscription.review.repository.ReviewRepository; + +@ExtendWith(MockitoExtension.class) +public class ReviewServiceTest { + + @Mock + ReviewRepository reviewRepo; + + // @Test + // public void testGetAllSubscriptionBoxReview() { + // ReviewService reviewService = new ReviewService(reviewRepo); + + // Optional review = Optional.of(new Review( + // 5, "amazing", "user1", "subsboxId" + // )); + + // when(reviewRepo.findById("subsboxId")).thenReturn(review); + + // Review foundReview = reviewService.getAllSubscriptionBoxReview("subsboxId"); + + // assertEquals(review.get(), foundReview); + + // verify(reviewRepo).findBySubscriptionBoxId("subsboxId"); + + // } + + + @Test + public void getReviewById() throws Exception { + ReviewService reviewService = new ReviewService(reviewRepo); + + Optional review = Optional.of(new Review( + 5, "amazing", "user1", "subsboxId" + )); + + String reviewId = review.get().getId(); + + when(reviewRepo.findById(reviewId)).thenReturn(review); + + Review foundReview = reviewService.findById(reviewId); + + assertEquals(foundReview, review.get()); + + verify(reviewRepo).findById(reviewId); + } + + @Test + public void getReviewByIdNotFound() { + ReviewService reviewService = new ReviewService(reviewRepo); + + Optional review = Optional.empty(); + + String reviewId = "reviewId"; + + when(reviewRepo.findById(reviewId)).thenReturn(review); + + assertThrows(ReviewNotFoundException.class, () -> { + reviewService.findById(reviewId); + }); + + verify(reviewRepo).findById(reviewId); + } + +} From 63aab459afe9c7f580892cf4deb1ce705a2229d0 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Tue, 30 Apr 2024 23:42:45 +0700 Subject: [PATCH 05/20] [RED] Add tests for Review Repository --- .../repository/ReviewRepositoryTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/java/snackscription/review/repository/ReviewRepositoryTest.java diff --git a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java new file mode 100644 index 0000000..496f0da --- /dev/null +++ b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java @@ -0,0 +1,53 @@ +package snackscription.review.repository; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import snackscription.review.model.Review; + +@DataJpaTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public class ReviewRepositoryTest { + @Autowired + private ReviewRepository reviewRepository; + + @Test + public void testFindBySubscriptionBoxId() { + List reviews = new ArrayList<>(); + reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); + reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); + + reviewRepository.saveAll(reviews); + + List foundReviews = reviewRepository.findBySubscriptionBoxId("subsbox_123"); + + assertEquals(reviews.size(), foundReviews.size()); + for (int i=0; i Date: Tue, 30 Apr 2024 23:56:46 +0700 Subject: [PATCH 06/20] [GREEN] Implement Review Repository --- .../review/repository/ReviewRepository.java | 8 ++++- .../repository/ReviewRepositoryTest.java | 34 +++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/snackscription/review/repository/ReviewRepository.java b/src/main/java/snackscription/review/repository/ReviewRepository.java index 0d7b6ce..096b38f 100644 --- a/src/main/java/snackscription/review/repository/ReviewRepository.java +++ b/src/main/java/snackscription/review/repository/ReviewRepository.java @@ -1,6 +1,12 @@ package snackscription.review.repository; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import snackscription.review.model.Review; -public interface ReviewRepository extends CrudRepository {} \ No newline at end of file +public interface ReviewRepository extends JpaRepository { + List findBySubscriptionBoxId(String subsboxId); + Review findBySubscriptionBoxIdAndUserId(String subsboxId, String userId); +} \ No newline at end of file diff --git a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java index 496f0da..147289f 100644 --- a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java +++ b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java @@ -19,28 +19,42 @@ public class ReviewRepositoryTest { @Autowired private ReviewRepository reviewRepository; + List reviews; - @Test - public void testFindBySubscriptionBoxId() { - List reviews = new ArrayList<>(); + @BeforeEach + public void setUp() { + this.reviews = new ArrayList<>(); reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); + reviews.add(new Review(2, "Lorem Ipsum", "user_124", "subsbox_124")); reviewRepository.saveAll(reviews); + } - List foundReviews = reviewRepository.findBySubscriptionBoxId("subsbox_123"); + @Test + public void testFindBySubscriptionBoxId() { + List curReviews = new ArrayList<>(); - assertEquals(reviews.size(), foundReviews.size()); - for (int i=0; i foundReviews = reviewRepository.findBySubscriptionBoxId(subsbox_id); + + assertEquals(curReviews.size(), foundReviews.size()); + for (int i=0; i Date: Wed, 1 May 2024 00:23:21 +0700 Subject: [PATCH 07/20] [RED] Add test for Review Repository delete operation --- .../review/repository/ReviewRepositoryTest.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java index 147289f..a41186c 100644 --- a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java +++ b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -9,11 +10,10 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - import snackscription.review.model.Review; +import static org.junit.jupiter.api.Assertions.*; + @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) public class ReviewRepositoryTest { @@ -58,6 +58,16 @@ public void testFindBySubscriptionBoxIdAndUserId() { assertEqualReview(review, foundReview); } + @Test + public void testDeleteBySubscriptionBoxIdAndUserId() { + Review review = this.reviews.getFirst(); + + reviewRepository.deleteBySubscriptionBoxIdAndUserId(review.getSubscriptionBoxId(), review.getUserId()); + Review foundReview = reviewRepository.findBySubscriptionBoxIdAndUserId(review.getSubscriptionBoxId(), review.getUserId()); + + assertNull(foundReview); + } + public void assertEqualReview(Review review1, Review review2) { assertEquals(review1.getRating(), review2.getRating()); assertEquals(review1.getContent(), review2.getContent()); From ca783b4482326714b5351f3c5fe273e14f0715ab Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 00:24:07 +0700 Subject: [PATCH 08/20] [GREEN] Implement Review Repository delete operation --- .../java/snackscription/review/repository/ReviewRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/snackscription/review/repository/ReviewRepository.java b/src/main/java/snackscription/review/repository/ReviewRepository.java index 096b38f..c0fb801 100644 --- a/src/main/java/snackscription/review/repository/ReviewRepository.java +++ b/src/main/java/snackscription/review/repository/ReviewRepository.java @@ -9,4 +9,5 @@ public interface ReviewRepository extends JpaRepository { List findBySubscriptionBoxId(String subsboxId); Review findBySubscriptionBoxIdAndUserId(String subsboxId, String userId); + void deleteBySubscriptionBoxIdAndUserId(String subsboxId, String userId); } \ No newline at end of file From 41621dcad7e2fd8660d94518410e8930e1f72411 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 00:49:14 +0700 Subject: [PATCH 09/20] [RED] Add test for review service --- .../review/service/ReviewServiceTest.java | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/test/java/snackscription/review/service/ReviewServiceTest.java b/src/test/java/snackscription/review/service/ReviewServiceTest.java index d1ee4e4..652f278 100644 --- a/src/test/java/snackscription/review/service/ReviewServiceTest.java +++ b/src/test/java/snackscription/review/service/ReviewServiceTest.java @@ -5,10 +5,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import javax.naming.spi.DirStateFactory.Result; +import javax.swing.text.html.Option; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -23,7 +27,11 @@ public class ReviewServiceTest { @Mock - ReviewRepository reviewRepo; + ReviewRepository reviewRepo; + + ReviewService reviewService; + + List reviews; // @Test // public void testGetAllSubscriptionBoxReview() { @@ -43,10 +51,19 @@ public class ReviewServiceTest { // } + @BeforeEach + public void setUp() { + reviewService = new ReviewService(reviewRepo); + + reviews = new ArrayList<>(); + reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); + reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); + reviews.add(new Review(2, "Lorem Ipsum", "user_124", "subsbox_124")); + } @Test public void getReviewById() throws Exception { - ReviewService reviewService = new ReviewService(reviewRepo); + Optional review = Optional.of(new Review( 5, "amazing", "user1", "subsboxId" @@ -74,10 +91,33 @@ public void getReviewByIdNotFound() { when(reviewRepo.findById(reviewId)).thenReturn(review); assertThrows(ReviewNotFoundException.class, () -> { - reviewService.findById(reviewId); - }); + reviewService.findById(reviewId); + }); verify(reviewRepo).findById(reviewId); } + + @Test + public void getReviewsBySubscriptionBoxId() { + ReviewService reviewService = new ReviewService(reviewRepo); + + List curReviews = new ArrayList<>(); + + String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); + for (Review review : this.reviews) { + if (review.getSubscriptionBoxId().equals(subscriptionBoxId)) { + curReviews.add(review); + } + } + + when(reviewRepo.findBySubscriptionBoxId(subscriptionBoxId)).thenReturn(curReviews); + + List foundReviews = reviewService.findBySubscriptionBoxId(subscriptionBoxId); + + assertEquals(curReviews, foundReviews); + + verify(reviewRepo).findBySubscriptionBoxId(subscriptionBoxId); + } + } From 8f694549b4ffe6dc0e0a4ae699389497cbf9f79e Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 00:49:59 +0700 Subject: [PATCH 10/20] [GREEN] Implement review service --- .../java/snackscription/review/service/ReviewService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/snackscription/review/service/ReviewService.java b/src/main/java/snackscription/review/service/ReviewService.java index 821e1f9..ad8a156 100644 --- a/src/main/java/snackscription/review/service/ReviewService.java +++ b/src/main/java/snackscription/review/service/ReviewService.java @@ -1,5 +1,6 @@ package snackscription.review.service; +import java.util.List; import java.util.Optional; import snackscription.review.exception.ReviewNotFoundException; @@ -22,4 +23,9 @@ public Review findById(String reviewId) throws ReviewNotFoundException { return oReview.get(); } + + public List findBySubscriptionBoxId(String subscriptionBoxId) { + return reviewRepository.findBySubscriptionBoxId(subscriptionBoxId); + } + } From 040c525c3aa1fbf86b79cb2d9b3e98bde6c24d6c Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 01:43:54 +0700 Subject: [PATCH 11/20] [RED] Add controller test for get reviews by subscription box id --- .../controller/ReviewControllerTest.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/test/java/snackscription/review/controller/ReviewControllerTest.java b/src/test/java/snackscription/review/controller/ReviewControllerTest.java index 602e464..c1b10f7 100644 --- a/src/test/java/snackscription/review/controller/ReviewControllerTest.java +++ b/src/test/java/snackscription/review/controller/ReviewControllerTest.java @@ -3,7 +3,12 @@ import static org.mockito.Mockito.verify; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import com.jayway.jsonpath.JsonPath; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -12,7 +17,9 @@ import org.springframework.http.MediaType; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; +import static org.junit.jupiter.api.Assertions.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -22,6 +29,7 @@ import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; +import org.springframework.test.web.servlet.result.JsonPathResultMatchers; import snackscription.review.model.Review; import snackscription.review.service.ReviewService; @@ -34,6 +42,16 @@ public class ReviewControllerTest { @Autowired MockMvc mockMvc; + List reviews; + + @BeforeEach + public void setUp() { + reviews = new ArrayList<>(); + reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); + reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); + reviews.add(new Review(2, "Lorem Ipsum", "user_124", "subsbox_124")); + } + // @Test // public void testGetAllSubscriptionBoxReview() { // String subsboxId = "subsboxId"; @@ -77,4 +95,56 @@ public void testGetById() throws Exception { verify(reviewService).findById(reviewId); } + + @Test + public void testGetBySubscriptionBoxId() throws Exception { + List curReviews = new ArrayList<>(); + + String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); + for (Review review : this.reviews) { + if (review.getSubscriptionBoxId().equals(subscriptionBoxId)) { + curReviews.add(review); + } + } + + when(reviewService.findBySubscriptionBoxId(subscriptionBoxId)).thenReturn(curReviews); + + String result = mockMvc.perform(get("/api/subscription-boxes/{subscriptionBoxId}", subscriptionBoxId)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(curReviews.size()))) + .andReturn() + .getResponse() + .getContentAsString(); + + List foundReviews = new ArrayList(); + for (int i=0; i cmp = new Comparator() { + @Override + public int compare(Review o1, Review o2) { + return o1.getUserId().compareTo(o2.getUserId()); + } + }; + + curReviews.sort(cmp); + foundReviews.sort(cmp); + + for (int i=0; i Date: Wed, 1 May 2024 01:44:27 +0700 Subject: [PATCH 12/20] [GREEN] Implement controller for get reviews by subscription box id --- .../review/controller/ReviewController.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/snackscription/review/controller/ReviewController.java b/src/main/java/snackscription/review/controller/ReviewController.java index f0921ca..4f52641 100644 --- a/src/main/java/snackscription/review/controller/ReviewController.java +++ b/src/main/java/snackscription/review/controller/ReviewController.java @@ -1,6 +1,7 @@ package snackscription.review.controller; import java.util.ArrayList; +import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -38,5 +39,11 @@ public ResponseEntity reviewPage() { @GetMapping("/api/reviews/{reviewId}") public Review getById(@PathVariable String reviewId) throws Exception { return reviewService.findById(reviewId); - } + } + + @GetMapping("/api/subscription-boxes/{subscriptionBoxId}") + public List getBySubscriptionBoxId(@PathVariable String subscriptionBoxId) throws Exception { + return reviewService.findBySubscriptionBoxId(subscriptionBoxId); + } + } \ No newline at end of file From 87920c8039a9e69a74aa56c8f27270e195a3df5f Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 02:28:52 +0700 Subject: [PATCH 13/20] Fix: update state implementation --- .../review/controller/ReviewController.java | 2 + .../snackscription/review/model/Review.java | 18 +++-- .../review/model/ReviewState.java | 71 +++++++++++++------ .../review/model/ReviewStateApproved.java | 19 ----- .../review/model/ReviewStatePending.java | 19 ----- .../review/model/ReviewStateRejected.java | 19 ----- .../review/service/ReviewService.java | 2 + .../review/model/ReviewTest.java | 40 +++++------ 8 files changed, 87 insertions(+), 103 deletions(-) delete mode 100644 src/main/java/snackscription/review/model/ReviewStateApproved.java delete mode 100644 src/main/java/snackscription/review/model/ReviewStatePending.java delete mode 100644 src/main/java/snackscription/review/model/ReviewStateRejected.java diff --git a/src/main/java/snackscription/review/controller/ReviewController.java b/src/main/java/snackscription/review/controller/ReviewController.java index 4f52641..16e6575 100644 --- a/src/main/java/snackscription/review/controller/ReviewController.java +++ b/src/main/java/snackscription/review/controller/ReviewController.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -20,6 +21,7 @@ @RequestMapping("/") public class ReviewController { + private ReviewService reviewService; public ReviewController(ReviewService reviewService) { diff --git a/src/main/java/snackscription/review/model/Review.java b/src/main/java/snackscription/review/model/Review.java index db90fff..fa3dde7 100644 --- a/src/main/java/snackscription/review/model/Review.java +++ b/src/main/java/snackscription/review/model/Review.java @@ -1,7 +1,6 @@ package snackscription.review.model; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import java.util.UUID; @@ -22,10 +21,11 @@ public class Review { @Column(name = "content", nullable = false) private String content; -// @Transient + @Setter - @ManyToOne - @JoinColumn(name = "state_id", nullable = false) + @Column(name = "state", nullable = false) +// @ManyToOne +// @JoinColumn(name = "state_id", nullable = false) private ReviewState state; @Column(name="user_id", nullable = false) @@ -41,7 +41,7 @@ public Review(int rating, String content, String userId, String subscriptionBoxI this.id = UUID.randomUUID().toString(); this.rating = rating; this.content = content; - this.state = new ReviewStatePending(this); + this.state = ReviewState.PENDING; this.userId = userId; this.subscriptionBoxId = subscriptionBoxId; } @@ -58,4 +58,12 @@ public void setRating(int rating) { } this.rating = rating; } + + public void approve() { + this.state.approve(this); + } + + public void reject() { + this.state.reject(this); + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewState.java b/src/main/java/snackscription/review/model/ReviewState.java index 802a321..e02e6de 100644 --- a/src/main/java/snackscription/review/model/ReviewState.java +++ b/src/main/java/snackscription/review/model/ReviewState.java @@ -1,36 +1,65 @@ package snackscription.review.model; -import jakarta.persistence.*; +public enum ReviewState { + PENDING("Pending", new PendingState()), + APPROVED("Approved", new ApprovedState()), + REJECTED("Rejected", new RejectedState()); + private final String name; + private final StateTransition state; + private ReviewState(String name, StateTransition state) { + this.name = name; + this.state = state; + } -@Entity -@Table(name = "review_state") -public abstract class ReviewState { + void approve(Review review) { + state.approve(review); + } + void reject(Review review) { + state.reject(review); + } - @Transient - Review review; + @Override + public String toString() { + return this.name; + } - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - Long id; + private interface StateTransition { + void approve(Review review); + void reject(Review review); + } - @Column(nullable = false) - String name; + private static class PendingState implements StateTransition { + @Override + public void approve(Review review) { + review.setState(APPROVED); + } - ReviewState(Review review) { - this.review = review; + @Override + public void reject(Review review) { + review.setState(REJECTED); + } } - public ReviewState() { + private static class ApprovedState implements StateTransition { + @Override + public void approve(Review review) { + throw new RuntimeException("Review already approved."); + } + @Override public void reject(Review review) { + review.setState(REJECTED); + } } - public abstract void approve(); - - public abstract void reject(); + private static class RejectedState implements StateTransition { + @Override + public void approve(Review review) { + review.setState(APPROVED); + } - @Override - public String toString() { - return this.name; + @Override public void reject(Review review) { + throw new RuntimeException("Review already rejected."); + } } -} \ No newline at end of file +} diff --git a/src/main/java/snackscription/review/model/ReviewStateApproved.java b/src/main/java/snackscription/review/model/ReviewStateApproved.java deleted file mode 100644 index 43d67ed..0000000 --- a/src/main/java/snackscription/review/model/ReviewStateApproved.java +++ /dev/null @@ -1,19 +0,0 @@ -package snackscription.review.model; - -public class ReviewStateApproved extends ReviewState { - - ReviewStateApproved(Review review) { - super(review); - this.name = "Approved"; - } - - @Override - public void approve() { - throw new RuntimeException("Review already approved."); - } - - @Override - public void reject() { - this.review.setState(new ReviewStateRejected(this.review)); - } -} \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStatePending.java b/src/main/java/snackscription/review/model/ReviewStatePending.java deleted file mode 100644 index efcb1f5..0000000 --- a/src/main/java/snackscription/review/model/ReviewStatePending.java +++ /dev/null @@ -1,19 +0,0 @@ -package snackscription.review.model; - -public class ReviewStatePending extends ReviewState { - - ReviewStatePending(Review review) { - super(review); - this.name = "Pending"; - } - - @Override - public void approve() { - this.review.setState(new ReviewStateApproved(this.review)); - } - - @Override - public void reject() { - this.review.setState(new ReviewStateRejected(this.review)); - } -} \ No newline at end of file diff --git a/src/main/java/snackscription/review/model/ReviewStateRejected.java b/src/main/java/snackscription/review/model/ReviewStateRejected.java deleted file mode 100644 index 90fa050..0000000 --- a/src/main/java/snackscription/review/model/ReviewStateRejected.java +++ /dev/null @@ -1,19 +0,0 @@ -package snackscription.review.model; - -public class ReviewStateRejected extends ReviewState { - - ReviewStateRejected(Review review) { - super(review); - this.name = "Rejected"; - } - - @Override - public void approve() { - this.review.setState(new ReviewStateApproved(this.review)); - } - - @Override - public void reject() { - throw new RuntimeException("Review already rejected."); - } -} \ No newline at end of file diff --git a/src/main/java/snackscription/review/service/ReviewService.java b/src/main/java/snackscription/review/service/ReviewService.java index ad8a156..e4259db 100644 --- a/src/main/java/snackscription/review/service/ReviewService.java +++ b/src/main/java/snackscription/review/service/ReviewService.java @@ -3,10 +3,12 @@ import java.util.List; import java.util.Optional; +import org.springframework.stereotype.Service; import snackscription.review.exception.ReviewNotFoundException; import snackscription.review.model.Review; import snackscription.review.repository.ReviewRepository; +@Service public class ReviewService { private ReviewRepository reviewRepository; diff --git a/src/test/java/snackscription/review/model/ReviewTest.java b/src/test/java/snackscription/review/model/ReviewTest.java index 74815f8..e2b2ee3 100644 --- a/src/test/java/snackscription/review/model/ReviewTest.java +++ b/src/test/java/snackscription/review/model/ReviewTest.java @@ -31,7 +31,7 @@ void testCreateReview() { assertEquals(userId, newReview.getUserId()); assertEquals(subscriptionBoxId, newReview.getSubscriptionBoxId()); assertNotNull(newReview.getId()); - assertEquals("Pending", newReview.getState().toString()); + assertEquals(ReviewState.PENDING, newReview.getState()); } @Test @@ -41,7 +41,7 @@ void testEditReview() { this.review.editReview(newRating, newContent); assertEquals(newRating, this.review.getRating()); assertEquals(newContent, this.review.getContent()); - assertEquals("Pending", this.review.getState().toString()); + assertEquals(ReviewState.PENDING, this.review.getState()); } @Test @@ -53,43 +53,43 @@ void testEditReviewInvalid() { @Test void testApprovePendingReview() { - this.review.setState(new ReviewStatePending(this.review)); - this.review.getState().approve(); - assertEquals("Approved", this.review.getState().toString()); + this.review.setState(ReviewState.PENDING); + this.review.approve(); + assertEquals(ReviewState.APPROVED, this.review.getState()); } @Test void testRejectPendingReview() { - this.review.setState(new ReviewStatePending(this.review)); - this.review.getState().reject(); - assertEquals("Rejected", this.review.getState().toString()); + this.review.setState(ReviewState.PENDING); + this.review.reject(); + assertEquals(ReviewState.REJECTED, this.review.getState()); } @Test void testApproveApprovedReview() { - this.review.setState(new ReviewStateApproved(this.review)); - assertThrows(RuntimeException.class, () -> this.review.getState().approve()); - assertEquals("Approved", this.review.getState().toString()); + this.review.setState(ReviewState.APPROVED); + assertThrows(RuntimeException.class, () -> this.review.approve()); + assertEquals(ReviewState.APPROVED, this.review.getState()); } @Test void testRejectApprovedReview() { - this.review.setState(new ReviewStateApproved(this.review)); - this.review.getState().reject(); - assertEquals("Rejected", this.review.getState().toString()); + this.review.setState(ReviewState.APPROVED); + this.review.reject(); + assertEquals(ReviewState.REJECTED, this.review.getState()); } @Test void testApproveRejectedReview() { - this.review.setState(new ReviewStateRejected(this.review)); - this.review.getState().approve(); - assertEquals("Approved", this.review.getState().toString()); + this.review.setState(ReviewState.REJECTED); + this.review.approve(); + assertEquals(ReviewState.APPROVED, this.review.getState()); } @Test void testRejectRejectedReview() { - this.review.setState(new ReviewStateRejected(this.review)); - assertThrows(RuntimeException.class, () -> this.review.getState().reject()); - assertEquals("Rejected", this.review.getState().toString()); + this.review.setState(ReviewState.REJECTED); + assertThrows(RuntimeException.class, () -> this.review.reject()); + assertEquals(ReviewState.REJECTED, this.review.getState()); } } \ No newline at end of file From e08138b7be67237be03b6374e5f185856a523228 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 12:01:42 +0700 Subject: [PATCH 14/20] [RED] Add repository test find by subscription box and state --- .../repository/ReviewRepositoryTest.java | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java index a41186c..a908ff8 100644 --- a/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java +++ b/src/test/java/snackscription/review/repository/ReviewRepositoryTest.java @@ -11,6 +11,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import snackscription.review.model.Review; +import snackscription.review.model.ReviewState; import static org.junit.jupiter.api.Assertions.*; @@ -24,9 +25,23 @@ public class ReviewRepositoryTest { @BeforeEach public void setUp() { this.reviews = new ArrayList<>(); - reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); - reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); - reviews.add(new Review(2, "Lorem Ipsum", "user_124", "subsbox_124")); + + Review review1 = new Review(5, "I love it", "user_123", "subsbox_123"); + Review review2 = new Review(1, "I hate it", "user_124", "subsbox_123"); + Review review3 = new Review(2, "Hmmmm idk", "user_124", "subsbox_124"); + Review review4 = new Review(3, "It's okay", "user_125", "subsbox_124"); + Review review5 = new Review(4, "I like it", "user_126", "subsbox_124"); + + review1.setState(ReviewState.PENDING); + review4.setState(ReviewState.APPROVED); + review5.setState(ReviewState.REJECTED); + + reviews = new ArrayList<>(); + reviews.add(review1); + reviews.add(review2); + reviews.add(review3); + reviews.add(review4); + reviews.add(review5); reviewRepository.saveAll(reviews); } @@ -50,6 +65,25 @@ public void testFindBySubscriptionBoxId() { } } + @Test + public void testFindBySubscriptionBoxIdAndState() { + List curReviews = new ArrayList<>(); + + String subsbox_id = this.reviews.getFirst().getSubscriptionBoxId(); + for (Review review : this.reviews) { + if (review.getSubscriptionBoxId().equals(subsbox_id) && review.getState().equals(ReviewState.APPROVED)){ + curReviews.add(review); + } + } + + List foundReviews = reviewRepository.findBySubscriptionBoxIdAndState(subsbox_id, ReviewState.APPROVED); + + assertEquals(curReviews.size(), foundReviews.size()); + for (int i=0; i Date: Wed, 1 May 2024 12:02:10 +0700 Subject: [PATCH 15/20] [GREEN] Implement repository find by subscription box id and state --- .../java/snackscription/review/repository/ReviewRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/snackscription/review/repository/ReviewRepository.java b/src/main/java/snackscription/review/repository/ReviewRepository.java index c0fb801..bb448bf 100644 --- a/src/main/java/snackscription/review/repository/ReviewRepository.java +++ b/src/main/java/snackscription/review/repository/ReviewRepository.java @@ -5,9 +5,11 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import snackscription.review.model.Review; +import snackscription.review.model.ReviewState; public interface ReviewRepository extends JpaRepository { List findBySubscriptionBoxId(String subsboxId); + List findBySubscriptionBoxIdAndState(String subsboxId, ReviewState state); Review findBySubscriptionBoxIdAndUserId(String subsboxId, String userId); void deleteBySubscriptionBoxIdAndUserId(String subsboxId, String userId); } \ No newline at end of file From d7e6adfd959b1b7899195c7dba38454b3323262c Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 12:02:31 +0700 Subject: [PATCH 16/20] [RED] Add review service test --- .../review/service/ReviewServiceTest.java | 130 +++++++++++++++++- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/src/test/java/snackscription/review/service/ReviewServiceTest.java b/src/test/java/snackscription/review/service/ReviewServiceTest.java index 652f278..264cb15 100644 --- a/src/test/java/snackscription/review/service/ReviewServiceTest.java +++ b/src/test/java/snackscription/review/service/ReviewServiceTest.java @@ -1,7 +1,9 @@ package snackscription.review.service; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,11 +18,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.internal.matchers.Null; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.web.servlet.ResultActions; import snackscription.review.exception.ReviewNotFoundException; import snackscription.review.model.Review; +import snackscription.review.model.ReviewState; import snackscription.review.repository.ReviewRepository; @ExtendWith(MockitoExtension.class) @@ -55,10 +59,22 @@ public class ReviewServiceTest { public void setUp() { reviewService = new ReviewService(reviewRepo); + Review review1 = new Review(5, "I love it", "user_123", "subsbox_123"); + Review review2 = new Review(1, "I hate it", "user_124", "subsbox_123"); + Review review3 = new Review(2, "Hmmmm idk", "user_124", "subsbox_124"); + Review review4 = new Review(3, "It's okay", "user_125", "subsbox_124"); + Review review5 = new Review(4, "I like it", "user_126", "subsbox_124"); + + review1.setState(ReviewState.PENDING); + review4.setState(ReviewState.APPROVED); + review5.setState(ReviewState.REJECTED); + reviews = new ArrayList<>(); - reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); - reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); - reviews.add(new Review(2, "Lorem Ipsum", "user_124", "subsbox_124")); + reviews.add(review1); + reviews.add(review2); + reviews.add(review3); + reviews.add(review4); + reviews.add(review5); } @Test @@ -119,5 +135,111 @@ public void getReviewsBySubscriptionBoxId() { verify(reviewRepo).findBySubscriptionBoxId(subscriptionBoxId); } - + @Test + public void testCreateReview() throws Exception { + Review review = reviews.getFirst(); + + when(reviewRepo.save(any(Review.class))).thenReturn(review); + + Review savedReview = reviewService.createReview( + review.getRating(), + review.getContent(), + review.getSubscriptionBoxId(), + review.getUserId()); + + assertEqualReview(review, savedReview); + + verify(reviewRepo).save(any(Review.class)); + } + + @Test + public void testGetAllSubscriptionBoxReview() throws Exception { + String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); + + List curReviews = new ArrayList<>(); + + for (Review review : this.reviews) { + if (review.getSubscriptionBoxId().equals(subscriptionBoxId)) { + curReviews.add(review); + } + } + + when(reviewRepo.findBySubscriptionBoxId(subscriptionBoxId)).thenReturn(curReviews); + + List foundReviews = reviewService.getAllSubscriptionBoxReview(subscriptionBoxId, null); + + assertEquals(curReviews, foundReviews); + + verify(reviewRepo).findBySubscriptionBoxId(subscriptionBoxId); + } + + @Test + public void testGetAllSubscriptionBoxReviewApproved() throws Exception { + String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); + + List cuReviews = new ArrayList<>(); + + for (Review review : this.reviews) { + if (review.getSubscriptionBoxId().equals(subscriptionBoxId) && review.getState().equals(ReviewState.APPROVED)) { + cuReviews.add(review); + } + } + + when(reviewRepo.findBySubscriptionBoxIdAndState(subscriptionBoxId, ReviewState.APPROVED)).thenReturn(cuReviews); + + List foundReviews = reviewService.getAllSubscriptionBoxReview(subscriptionBoxId, "APPROVED"); + + assertEquals(cuReviews, foundReviews); + + verify(reviewRepo).findBySubscriptionBoxIdAndState(subscriptionBoxId, ReviewState.APPROVED); + } + + @Test + public void testEditReview() throws Exception { + Review review = reviews.getFirst(); + String subscriptionBoxId = review.getSubscriptionBoxId(); + String userId = review.getUserId(); + + int newRating = 1; + String newContent = "Changed content"; + Review newReview = new Review(newRating, newContent, userId, subscriptionBoxId); + newReview.setId(review.getId()); + + when(reviewRepo.findBySubscriptionBoxIdAndUserId(subscriptionBoxId, userId)).thenReturn(review); + when(reviewRepo.save(any(Review.class))).thenReturn(newReview); + + Review editedReview = reviewService.editReview(newRating, newContent, subscriptionBoxId, userId); + + assertEquals(newRating, editedReview.getRating()); + assertEquals(newContent, editedReview.getContent()); + assertEquals(subscriptionBoxId, editedReview.getSubscriptionBoxId()); + assertEquals(userId, editedReview.getUserId()); + assertEquals(review.getId(), editedReview.getId()); + } + + @Test + public void testDeleteReview() throws Exception { + String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); + String userId = this.reviews.getFirst().getUserId(); + + Review review = reviews.getFirst(); + + when(reviewRepo.findBySubscriptionBoxIdAndUserId(subscriptionBoxId, userId)).thenReturn(review); + + reviewService.deleteReview(subscriptionBoxId, userId); + + when(reviewRepo.findBySubscriptionBoxIdAndUserId(subscriptionBoxId, userId)).thenReturn(null); + + assertNull(reviewService.getReview(subscriptionBoxId, userId)); + + verify(reviewRepo).delete(review); + } + + public void assertEqualReview(Review review1, Review review2) { + assertEquals(review1.getRating(), review2.getRating()); + assertEquals(review1.getContent(), review2.getContent()); + assertEquals(review1.getUserId(), review2.getUserId()); + assertEquals(review1.getSubscriptionBoxId(), review2.getSubscriptionBoxId()); + } } + From 40d1a725d5925c32914a94726e4dfaf637667dd8 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 12:02:42 +0700 Subject: [PATCH 17/20] [GREEN] Implement review service functionality --- .../review/exception/ControllerAdvisor.java | 5 ++ .../exception/InvalidStateException.java | 4 ++ .../snackscription/review/model/Review.java | 7 +-- .../review/model/ReviewState.java | 16 ++----- .../review/service/ReviewService.java | 48 +++++++++++++++++++ 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 src/main/java/snackscription/review/exception/InvalidStateException.java diff --git a/src/main/java/snackscription/review/exception/ControllerAdvisor.java b/src/main/java/snackscription/review/exception/ControllerAdvisor.java index 41859f8..c0ab14d 100644 --- a/src/main/java/snackscription/review/exception/ControllerAdvisor.java +++ b/src/main/java/snackscription/review/exception/ControllerAdvisor.java @@ -15,4 +15,9 @@ public class ControllerAdvisor extends ResponseEntityExceptionHandler { public ResponseEntity handleReviewNotFound(ReviewNotFoundException exc, WebRequest req) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } + + @ExceptionHandler(InvalidStateException.class) + public ResponseEntity handleInvalidState(InvalidStateException exc, WebRequest req) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } } diff --git a/src/main/java/snackscription/review/exception/InvalidStateException.java b/src/main/java/snackscription/review/exception/InvalidStateException.java new file mode 100644 index 0000000..a15690e --- /dev/null +++ b/src/main/java/snackscription/review/exception/InvalidStateException.java @@ -0,0 +1,4 @@ +package snackscription.review.exception; + +public class InvalidStateException extends Exception { +} diff --git a/src/main/java/snackscription/review/model/Review.java b/src/main/java/snackscription/review/model/Review.java index fa3dde7..572d7a5 100644 --- a/src/main/java/snackscription/review/model/Review.java +++ b/src/main/java/snackscription/review/model/Review.java @@ -8,6 +8,7 @@ @Getter +@Setter @Entity @Table(name = "review") public class Review { @@ -17,15 +18,10 @@ public class Review { @Column(name = "rating", nullable = false) private int rating; - @Setter @Column(name = "content", nullable = false) private String content; - - @Setter @Column(name = "state", nullable = false) -// @ManyToOne -// @JoinColumn(name = "state_id", nullable = false) private ReviewState state; @Column(name="user_id", nullable = false) @@ -46,7 +42,6 @@ public Review(int rating, String content, String userId, String subscriptionBoxI this.subscriptionBoxId = subscriptionBoxId; } - public void editReview(int rating, String content) { this.setRating(rating); this.setContent(content); diff --git a/src/main/java/snackscription/review/model/ReviewState.java b/src/main/java/snackscription/review/model/ReviewState.java index e02e6de..3ed1ac8 100644 --- a/src/main/java/snackscription/review/model/ReviewState.java +++ b/src/main/java/snackscription/review/model/ReviewState.java @@ -1,14 +1,11 @@ package snackscription.review.model; public enum ReviewState { - PENDING("Pending", new PendingState()), - APPROVED("Approved", new ApprovedState()), - REJECTED("Rejected", new RejectedState()); - - private final String name; + PENDING(new PendingState()), + APPROVED(new ApprovedState()), + REJECTED(new RejectedState()); private final StateTransition state; - private ReviewState(String name, StateTransition state) { - this.name = name; + private ReviewState(StateTransition state) { this.state = state; } @@ -19,11 +16,6 @@ void reject(Review review) { state.reject(review); } - @Override - public String toString() { - return this.name; - } - private interface StateTransition { void approve(Review review); void reject(Review review); diff --git a/src/main/java/snackscription/review/service/ReviewService.java b/src/main/java/snackscription/review/service/ReviewService.java index e4259db..220d3ef 100644 --- a/src/main/java/snackscription/review/service/ReviewService.java +++ b/src/main/java/snackscription/review/service/ReviewService.java @@ -4,8 +4,11 @@ import java.util.Optional; import org.springframework.stereotype.Service; + +import snackscription.review.exception.InvalidStateException; import snackscription.review.exception.ReviewNotFoundException; import snackscription.review.model.Review; +import snackscription.review.model.ReviewState; import snackscription.review.repository.ReviewRepository; @Service @@ -30,4 +33,49 @@ public List findBySubscriptionBoxId(String subscriptionBoxId) { return reviewRepository.findBySubscriptionBoxId(subscriptionBoxId); } + public Review createReview(int rating, String content, String subscriptionBoxId, String userId) throws Exception { + Review review = new Review(rating, content, userId, subscriptionBoxId); + reviewRepository.save(review); + return review; + } + + public List getAllSubscriptionBoxReview(String subscriptionBoxId, String state) throws Exception { + if (state == null) { + return reviewRepository.findBySubscriptionBoxId(subscriptionBoxId); + } else { + state = state.toUpperCase(); + ReviewState reviewState = Enum.valueOf(ReviewState.class, state); + if (reviewState == null) { + throw new InvalidStateException(); + } + return reviewRepository.findBySubscriptionBoxIdAndState(subscriptionBoxId, reviewState); + } + } + + public Review getReview(String subscriptionBoxId, String userId) throws Exception { + return reviewRepository.findBySubscriptionBoxIdAndUserId(subscriptionBoxId, userId); + } + + public Review editReview(int rating, String content, String subscriptionBoxId, String userId) throws Exception { + Review review = reviewRepository.findBySubscriptionBoxIdAndUserId(subscriptionBoxId, userId); + + if (review == null) { + throw new ReviewNotFoundException(); + } + + review.setRating(rating); + review.setContent(content); + + return reviewRepository.save(review); + } + + public void deleteReview(String subscriptionBoxId, String userId) throws Exception { + Review review = reviewRepository.findBySubscriptionBoxIdAndUserId(subscriptionBoxId, userId); + + if (review == null) { + throw new ReviewNotFoundException(); + } + + reviewRepository.delete(review); + } } From 6e903f74518446611c0ad925d205fb8b96803994 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 14:06:15 +0700 Subject: [PATCH 18/20] [RED] Add test for review controller --- .../controller/ReviewControllerTest.java | 167 +++++++++++------- 1 file changed, 103 insertions(+), 64 deletions(-) diff --git a/src/test/java/snackscription/review/controller/ReviewControllerTest.java b/src/test/java/snackscription/review/controller/ReviewControllerTest.java index c1b10f7..057699a 100644 --- a/src/test/java/snackscription/review/controller/ReviewControllerTest.java +++ b/src/test/java/snackscription/review/controller/ReviewControllerTest.java @@ -77,74 +77,113 @@ public void setUp() { // verify(reviewService).testGetAllSubscriptionBoxReview(subsboxId); // } +// @Test +// public void testGetById() throws Exception { +// Review review = new Review( +// 5, "amazing", "user1", "subsboxId" +// ); +// String reviewId = review.getId(); +// +// when(reviewService.findById(reviewId)).thenReturn(review); +// +// ResultActions result = mockMvc.perform(get("/api/reviews/{reviewId}", reviewId)) +// .andExpect(status().isOk()) +// .andExpect(jsonPath("$.rating", is(5))) +// .andExpect(jsonPath("$.content", is("amazing"))) +// .andExpect(jsonPath("$.userId", is("user1"))) +// .andExpect(jsonPath("$.subscriptionBoxId", is("subsboxId"))); +// +// verify(reviewService).findById(reviewId); +// } + +// @Test +// public void testGetBySubscriptionBoxId() throws Exception { +// List curReviews = new ArrayList<>(); +// +// String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); +// for (Review review : this.reviews) { +// if (review.getSubscriptionBoxId().equals(subscriptionBoxId)) { +// curReviews.add(review); +// } +// } +// +// when(reviewService.findBySubscriptionBoxId(subscriptionBoxId)).thenReturn(curReviews); +// +// String result = mockMvc.perform(get("/api/subscription-boxes/{subscriptionBoxId}", subscriptionBoxId)) +// .andExpect(status().isOk()) +// .andExpect(jsonPath("$", hasSize(curReviews.size()))) +// .andReturn() +// .getResponse() +// .getContentAsString(); +// +// List foundReviews = new ArrayList(); +// for (int i=0; i cmp = new Comparator() { +// @Override +// public int compare(Review o1, Review o2) { +// return o1.getUserId().compareTo(o2.getUserId()); +// } +// }; +// +// curReviews.sort(cmp); +// foundReviews.sort(cmp); +// +// for (int i=0; i curReviews = new ArrayList<>(); - - String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); - for (Review review : this.reviews) { - if (review.getSubscriptionBoxId().equals(subscriptionBoxId)) { - curReviews.add(review); - } - } - - when(reviewService.findBySubscriptionBoxId(subscriptionBoxId)).thenReturn(curReviews); - - String result = mockMvc.perform(get("/api/subscription-boxes/{subscriptionBoxId}", subscriptionBoxId)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$", hasSize(curReviews.size()))) - .andReturn() - .getResponse() - .getContentAsString(); - - List foundReviews = new ArrayList(); - for (int i=0; i cmp = new Comparator() { - @Override - public int compare(Review o1, Review o2) { - return o1.getUserId().compareTo(o2.getUserId()); - } - }; - - curReviews.sort(cmp); - foundReviews.sort(cmp); - - for (int i=0; i Date: Wed, 1 May 2024 14:06:26 +0700 Subject: [PATCH 19/20] [GREEN] Implement review controller --- .../review/controller/ReviewController.java | 87 +++++++++++++++++-- .../review/service/ReviewService.java | 12 +++ 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/src/main/java/snackscription/review/controller/ReviewController.java b/src/main/java/snackscription/review/controller/ReviewController.java index 16e6575..b0b3d01 100644 --- a/src/main/java/snackscription/review/controller/ReviewController.java +++ b/src/main/java/snackscription/review/controller/ReviewController.java @@ -2,8 +2,12 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; +import org.apache.catalina.connector.Response; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Resource; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -15,6 +19,11 @@ import snackscription.review.service.ReviewService; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.PutMapping; + + @RestController @@ -33,19 +42,83 @@ public ResponseEntity reviewPage() { return ResponseEntity.ok().body("Welcome to the review service!"); } - // @GetMapping("/api/subscription-boxes/{subsboxId}") - // public ArrayList getAllSubscriptionBoxReview(@PathVariable String subsboxId) throws Exception { - // return reviewService.getAllSubscriptionBoxReview(subsboxId); - // } + @PostMapping("/api/subscription-boxes/{subscriptionBoxId}") + public ResponseEntity createSubscriptionBoxReview(@RequestBody Map body, @PathVariable String subscriptionBoxId) { + + try { + String userId = body.get("userId"); + int rating = Integer.parseInt(body.get("rating")); + String content = body.get("content"); + + Review review = reviewService.createReview(rating, content, subscriptionBoxId, userId); + return new ResponseEntity<>(review, HttpStatus.CREATED); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + + @GetMapping("/api/subscription-boxes/{subscriptionBoxId}") + public ResponseEntity> getAllPublicSubscriptionBoxReview(@PathVariable String subscriptionBoxId) { + try { + List reviews = reviewService.getAllSubscriptionBoxReview(subscriptionBoxId, "APPROVED"); + return new ResponseEntity<>(reviews, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + + @GetMapping("/api/subscription-boxes/{subscriptionBoxId}/users/self") + public ResponseEntity getSelfSubscriptionBoxReview(@RequestBody Map body, @PathVariable String subscriptionBoxId) { + try { + String userId = body.get("userId"); + Review review = reviewService.getReview(subscriptionBoxId, userId); + return new ResponseEntity<>(review, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + + @PutMapping("/api/subscription-boxes/{subscriptionBoxId}/users/self") + public ResponseEntity editSelfSubscriptionBoxId(@RequestBody Map body, @PathVariable String subscriptionBoxId) { + try { + String userId = body.get("userId"); + int rating = Integer.parseInt(body.get("rating")); + String content = body.get("content"); + + Review review = reviewService.editReview(rating, content, subscriptionBoxId, userId); + return new ResponseEntity<>(review, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + + @GetMapping("/api/reviews/{subsboxId}") + public List getBySubscriptionBoxId(@PathVariable String subsboxId) throws Exception { + return reviewService.getAllSubscriptionBoxReview(subsboxId, null); + } @GetMapping("/api/reviews/{reviewId}") public Review getById(@PathVariable String reviewId) throws Exception { return reviewService.findById(reviewId); } - @GetMapping("/api/subscription-boxes/{subscriptionBoxId}") - public List getBySubscriptionBoxId(@PathVariable String subscriptionBoxId) throws Exception { - return reviewService.findBySubscriptionBoxId(subscriptionBoxId); + @PutMapping("/api/reviews/{reviewId}/approve") + public ResponseEntity approveReview(@PathVariable String reviewId) { + try { + Review review = reviewService.approveReview(reviewId); + return new ResponseEntity<>(review, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } } + @PutMapping("/api/reviews/{reviewId}/reject") + public ResponseEntity rejectReview(@PathVariable String reviewId) { + try { + Review review = reviewService.rejectReview(reviewId); + return new ResponseEntity<>(review, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } } \ No newline at end of file diff --git a/src/main/java/snackscription/review/service/ReviewService.java b/src/main/java/snackscription/review/service/ReviewService.java index 220d3ef..bcd511a 100644 --- a/src/main/java/snackscription/review/service/ReviewService.java +++ b/src/main/java/snackscription/review/service/ReviewService.java @@ -78,4 +78,16 @@ public void deleteReview(String subscriptionBoxId, String userId) throws Excepti reviewRepository.delete(review); } + + public Review approveReview(String reviewId) throws Exception { + Review review = findById(reviewId); + review.approve(); + return reviewRepository.save(review); + } + + public Review rejectReview(String reviewId) throws Exception { + Review review = findById(reviewId); + review.reject(); + return reviewRepository.save(review); + } } From a9ea2c19da691490c759dee183cb89ab73602f17 Mon Sep 17 00:00:00 2001 From: asteriskzie Date: Wed, 1 May 2024 20:18:32 +0700 Subject: [PATCH 20/20] [FIX] Fix controller test and implementation --- .../review/controller/ReviewController.java | 22 ++ .../controller/ReviewControllerTest.java | 319 +++++++++++++----- 2 files changed, 264 insertions(+), 77 deletions(-) diff --git a/src/main/java/snackscription/review/controller/ReviewController.java b/src/main/java/snackscription/review/controller/ReviewController.java index b0b3d01..4b89ab2 100644 --- a/src/main/java/snackscription/review/controller/ReviewController.java +++ b/src/main/java/snackscription/review/controller/ReviewController.java @@ -10,6 +10,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -92,6 +93,27 @@ public ResponseEntity editSelfSubscriptionBoxId(@RequestBody Map deleteSelfSubscriptionBoxReview(@RequestBody Map body, @PathVariable String subscriptionBoxId) { + try { + String userId = body.get("userId"); + reviewService.deleteReview(subscriptionBoxId, userId); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + + @DeleteMapping("/api/subscription-boxes/{subscriptionBoxId}/users/{userId}") + public ResponseEntity deleteSubscriptionBoxReview(@PathVariable String subscriptionBoxId, @PathVariable String userId) { + try { + reviewService.deleteReview(subscriptionBoxId, userId); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } catch (Exception e) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } + @GetMapping("/api/reviews/{subsboxId}") public List getBySubscriptionBoxId(@PathVariable String subsboxId) throws Exception { return reviewService.getAllSubscriptionBoxReview(subsboxId, null); diff --git a/src/test/java/snackscription/review/controller/ReviewControllerTest.java b/src/test/java/snackscription/review/controller/ReviewControllerTest.java index 057699a..764efdc 100644 --- a/src/test/java/snackscription/review/controller/ReviewControllerTest.java +++ b/src/test/java/snackscription/review/controller/ReviewControllerTest.java @@ -1,5 +1,6 @@ package snackscription.review.controller; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import java.util.ArrayList; @@ -11,6 +12,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.internal.stubbing.answers.DoesNothing; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -24,13 +26,17 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import org.springframework.test.web.servlet.result.JsonPathResultMatchers; import snackscription.review.model.Review; +import snackscription.review.model.ReviewState; import snackscription.review.service.ReviewService; @ExtendWith(SpringExtension.class) @@ -46,36 +52,234 @@ public class ReviewControllerTest { @BeforeEach public void setUp() { + this.reviews = new ArrayList<>(); + + Review review1 = new Review(5, "I love it", "user_123", "subsbox_123"); + Review review2 = new Review(1, "I hate it", "user_124", "subsbox_123"); + Review review3 = new Review(2, "Hmmmm idk", "user_124", "subsbox_124"); + Review review4 = new Review(3, "It's okay", "user_125", "subsbox_124"); + Review review5 = new Review(4, "I like it", "user_126", "subsbox_124"); + + review1.setState(ReviewState.PENDING); + review4.setState(ReviewState.APPROVED); + review5.setState(ReviewState.REJECTED); + reviews = new ArrayList<>(); - reviews.add(new Review(5, "Bagus banget", "user_123", "subsbox_123")); - reviews.add(new Review(1, "Jelek banget", "user_124", "subsbox_123")); - reviews.add(new Review(2, "Lorem Ipsum", "user_124", "subsbox_124")); + reviews.add(review1); + reviews.add(review2); + reviews.add(review3); + reviews.add(review4); + reviews.add(review5); + } + + @Test + public void testCreateSubscriptionBoxReview() throws Exception{ + Review review = reviews.getFirst(); + + when(reviewService.createReview(review.getRating(), review.getContent(), review.getSubscriptionBoxId(), review.getUserId())).thenReturn(review); + + ResultActions result = mockMvc.perform(post("/api/subscription-boxes/{subscriptionBoxId}", review.getSubscriptionBoxId()) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"rating\": 5, \"content\": \"I love it\", \"userId\": \"user_123\"}")) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.rating", is(5))) + .andExpect(jsonPath("$.content", is("I love it"))) + .andExpect(jsonPath("$.userId", is("user_123"))) + .andExpect(jsonPath("$.subscriptionBoxId", is("subsbox_123"))); + + verify(reviewService).createReview(review.getRating(), review.getContent(), review.getSubscriptionBoxId(), review.getUserId()); + } + + @Test + public void testReadAllPublicSubscriptionBoxReview() throws Exception { + List approvedReviews = new ArrayList<>(); + String subsboxId = "subsbox_124"; + for (Review review : reviews) { + if (review.getSubscriptionBoxId().equals(subsboxId) && review.getState().equals(ReviewState.APPROVED)) { + approvedReviews.add(review); + } + } + + when(reviewService.getAllSubscriptionBoxReview(subsboxId, "APPROVED")).thenReturn(approvedReviews); + + String result = mockMvc.perform(get("/api/subscription-boxes/{subscriptionBoxId}", subsboxId)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(approvedReviews.size()))) + .andReturn() + .getResponse() + .getContentAsString(); + + List foundReviews = new ArrayList(); + for (int i=0; i cmp = new Comparator() { + @Override + public int compare(Review o1, Review o2) { + return o1.getUserId().compareTo(o2.getUserId()); + } + }; + + approvedReviews.sort(cmp); + foundReviews.sort(cmp); + + for (int i=0; i reviews = new ArrayList<>(); - // reviews.add(new Review(5, "amazing", "user1", subsboxId)); - // reviews.add(new Review(4, "good", "user2", subsboxId)); - - // when(reviewService.testGetAllSubscriptionBoxReview(subsboxId)).thenReturn(reviews); - - // ResultActions result = mockMvc.perform(get("/api/subscription-boxes/{subsboxId}", subsboxId)) - // .andExpect(status().isOk()) - // .andExpect(jsonPath("$", hasSize(2))) - // .andExpect(jsonPath("$[0].rating", is(5))) - // .andExpect(jsonPath("$[0].content", is("amazing"))) - // .andExpect(jsonPath("$[0].userId", is("user1"))) - // .andExpect(jsonPath("$[0].subscriptionBoxId", is(subsboxId))) - // .andExpect(jsonPath("$[1].rating", is(4))) - // .andExpect(jsonPath("$[1].content", is("good"))) - // .andExpect(jsonPath("$[1].userId", is("user2"))) - // .andExpect(jsonPath("$[1].subscriptionBoxId", is(subsboxId))); +// @Test +// public void testGetAllSubscriptionBoxReview() { +// String subsboxId = "subsboxId"; + +// ArrayList reviews = new ArrayList<>(); +// reviews.add(new Review(5, "amazing", "user1", subsboxId)); +// reviews.add(new Review(4, "good", "user2", subsboxId)); + +// when(reviewService.testGetAllSubscriptionBoxReview(subsboxId)).thenReturn(reviews); + +// ResultActions result = mockMvc.perform(get("/api/subscription-boxes/{subsboxId}", subsboxId)) +// .andExpect(status().isOk()) +// .andExpect(jsonPath("$", hasSize(2))) +// .andExpect(jsonPath("$[0].rating", is(5))) +// .andExpect(jsonPath("$[0].content", is("amazing"))) +// .andExpect(jsonPath("$[0].userId", is("user1"))) +// .andExpect(jsonPath("$[0].subscriptionBoxId", is(subsboxId))) +// .andExpect(jsonPath("$[1].rating", is(4))) +// .andExpect(jsonPath("$[1].content", is("good"))) +// .andExpect(jsonPath("$[1].userId", is("user2"))) +// .andExpect(jsonPath("$[1].subscriptionBoxId", is(subsboxId))); - // verify(reviewService).testGetAllSubscriptionBoxReview(subsboxId); - // } +// verify(reviewService).testGetAllSubscriptionBoxReview(subsboxId); +// } // @Test // public void testGetById() throws Exception { @@ -83,39 +287,39 @@ public void setUp() { // 5, "amazing", "user1", "subsboxId" // ); // String reviewId = review.getId(); -// + // when(reviewService.findById(reviewId)).thenReturn(review); -// + // ResultActions result = mockMvc.perform(get("/api/reviews/{reviewId}", reviewId)) // .andExpect(status().isOk()) // .andExpect(jsonPath("$.rating", is(5))) // .andExpect(jsonPath("$.content", is("amazing"))) // .andExpect(jsonPath("$.userId", is("user1"))) // .andExpect(jsonPath("$.subscriptionBoxId", is("subsboxId"))); -// + // verify(reviewService).findById(reviewId); // } // @Test // public void testGetBySubscriptionBoxId() throws Exception { // List curReviews = new ArrayList<>(); -// + // String subscriptionBoxId = this.reviews.getFirst().getSubscriptionBoxId(); // for (Review review : this.reviews) { // if (review.getSubscriptionBoxId().equals(subscriptionBoxId)) { // curReviews.add(review); // } // } -// + // when(reviewService.findBySubscriptionBoxId(subscriptionBoxId)).thenReturn(curReviews); -// + // String result = mockMvc.perform(get("/api/subscription-boxes/{subscriptionBoxId}", subscriptionBoxId)) // .andExpect(status().isOk()) // .andExpect(jsonPath("$", hasSize(curReviews.size()))) // .andReturn() // .getResponse() // .getContentAsString(); -// + // List foundReviews = new ArrayList(); // for (int i=0; i cmp = new Comparator() { // @Override // public int compare(Review o1, Review o2) { // return o1.getUserId().compareTo(o2.getUserId()); // } // }; -// + // curReviews.sort(cmp); // foundReviews.sort(cmp); -// + // for (int i=0; i