-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Created empty files for individual layers * Added mongodb configs * Added cart model * Added repository * Updated repository * Created service layer * Minor change * Added rest endpoints for application * Added existByUserId function * Update service layer * Updated controller layer * Added custom page request to support pageable * Changes done to support pageable * Remove pageable from get cart * Remove fixture * Add unit tests (#16) * Created test file and added add product to cart unit test * Fixed typo * Added one more unit test for adding product in cart * FIXED detekt build fail * Remove unuse param * Added more unit test * Remove unused function * Minor change * Added more unit tests * FIXED: Logic of empty cart * Added more unit tests
- Loading branch information
Showing
6 changed files
with
310 additions
and
1 deletion.
There are no files selected for viewing
55 changes: 55 additions & 0 deletions
55
src/main/kotlin/com/example/backendcart/controller/CartController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.example.backendcart.controller | ||
|
||
import com.example.backendcart.model.Cart | ||
import com.example.backendcart.service.CartService | ||
import org.springframework.beans.factory.annotation.Autowired | ||
import org.springframework.http.server.reactive.ServerHttpResponse | ||
import org.springframework.web.bind.annotation.* | ||
import java.util.* | ||
|
||
@RestController | ||
@RequestMapping("/cart") | ||
class CartController ( | ||
@Autowired | ||
private val cartService: CartService | ||
) | ||
{ | ||
@PostMapping | ||
fun addProductInCart(@RequestBody cart: Cart, response: ServerHttpResponse) = | ||
cartService.addProductToCart(cart, response) | ||
@GetMapping("/{userId}/{productId}") | ||
fun getProductQuantityInCart( | ||
@PathVariable productId: String, | ||
@PathVariable userId: String | ||
) = | ||
cartService.getProductQuantityInCart(userId, productId) | ||
@GetMapping("/{userId}") | ||
fun getUserCart(@PathVariable userId: String) = | ||
cartService.getUserCart(userId) | ||
@PutMapping | ||
fun updateProductQuantity( | ||
@RequestBody cart: Cart, | ||
response: ServerHttpResponse | ||
) = | ||
cartService.updateProductQuantity(cart, response) | ||
@DeleteMapping("/{userId}/{productId}") | ||
fun deleteProductFromCart( | ||
@PathVariable productId: String, | ||
@PathVariable userId: String, | ||
response: ServerHttpResponse | ||
) = | ||
cartService.deleteProductFromCart( | ||
userId, | ||
productId, | ||
response | ||
) | ||
@DeleteMapping("/{userId}") | ||
fun emptyCart( | ||
@PathVariable userId: String, | ||
response: ServerHttpResponse | ||
) = | ||
cartService.emptyUserCart( | ||
userId, | ||
response | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.example.backendcart.model | ||
|
||
import org.springframework.data.mongodb.core.index.CompoundIndex | ||
import org.springframework.data.mongodb.core.mapping.Document | ||
|
||
@CompoundIndex(name = "cart_idx", def = "{'userId': 1, 'productId': 1}", | ||
unique = true) | ||
@Document("Cart") | ||
data class Cart ( | ||
val userId: String, | ||
val productId: String, | ||
val quantity: Int | ||
) |
17 changes: 17 additions & 0 deletions
17
src/main/kotlin/com/example/backendcart/repository/CartRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.example.backendcart.repository | ||
|
||
import com.example.backendcart.model.Cart | ||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository | ||
import org.springframework.stereotype.Repository | ||
import reactor.core.publisher.Flux | ||
import reactor.core.publisher.Mono | ||
|
||
@Repository | ||
interface CartRepository : ReactiveMongoRepository<Cart, String> { | ||
fun findByUserId(userId: String): Flux<Cart> | ||
fun findByUserIdAndProductId(userId: String, productId: String): Mono<Cart> | ||
fun existsByUserIdAndProductId(userId: String, productId: String): Mono<Boolean> | ||
fun existsByUserId(userId: String): Mono<Boolean> | ||
fun deleteByUserIdAndProductId(userId: String, productId: String): Mono<Void> | ||
fun deleteByUserId(userId: String): Flux<Void> | ||
} |
77 changes: 77 additions & 0 deletions
77
src/main/kotlin/com/example/backendcart/service/CartService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.example.backendcart.service | ||
|
||
import com.example.backendcart.model.Cart | ||
import com.example.backendcart.repository.CartRepository | ||
import org.springframework.beans.factory.annotation.Autowired | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.server.reactive.ServerHttpResponse | ||
import org.springframework.stereotype.Service | ||
import reactor.core.publisher.Mono | ||
|
||
@Service | ||
class CartService ( | ||
@Autowired | ||
private val cartRepository: CartRepository | ||
) | ||
{ | ||
fun addProductToCart(cart: Cart, response: ServerHttpResponse) = | ||
cartRepository.insert(cart) | ||
.map { | ||
response.statusCode = HttpStatus.OK | ||
"Product added to cart" | ||
} | ||
.onErrorResume { | ||
response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR | ||
Mono.just("Product already exist in cart") | ||
} | ||
fun getProductQuantityInCart(userId: String, productId: String) = | ||
cartRepository.findByUserIdAndProductId(userId, productId) | ||
.map{ | ||
it.quantity | ||
} | ||
.defaultIfEmpty(0) | ||
fun getUserCart(userId: String) = | ||
cartRepository.findByUserId(userId) | ||
.map { | ||
it.productId | ||
} | ||
fun updateProductQuantity(cart: Cart, response: ServerHttpResponse) = | ||
cartRepository.existsByUserIdAndProductId(cart.userId, cart.productId) | ||
.flatMap { | ||
if (it) { | ||
cartRepository.deleteByUserIdAndProductId(cart.userId, cart.productId) | ||
.flatMap { | ||
cartRepository.insert(cart) | ||
} | ||
.then(Mono.just("Product quantity updated")) | ||
} | ||
else { | ||
response.statusCode = HttpStatus.NOT_FOUND | ||
Mono.just("Product not found") | ||
} | ||
} | ||
fun deleteProductFromCart(userId: String, productId: String, response: ServerHttpResponse) = | ||
cartRepository.existsByUserIdAndProductId(userId, productId) | ||
.flatMap { | ||
if (it) { | ||
cartRepository.deleteByUserIdAndProductId(userId, productId) | ||
.then(Mono.just("Product removed from cart")) | ||
} | ||
else { | ||
response.statusCode = HttpStatus.NOT_FOUND | ||
Mono.just("Product not found in cart") | ||
} | ||
} | ||
fun emptyUserCart(userId: String, response: ServerHttpResponse) = | ||
cartRepository.existsByUserId(userId) | ||
.flatMap { | ||
if (! it) { | ||
response.statusCode = HttpStatus.NOT_FOUND | ||
Mono.just("Cart not found") | ||
} | ||
else { | ||
cartRepository.deleteByUserId(userId) | ||
.then(Mono.just("Successful")) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
|
||
spring.data.mongodb.uri=${MONGODB_URI} | ||
spring.data.mongodb.database=HRV-Mart-Backend-Cart | ||
server.port=${APPLICATION_PORT} |
145 changes: 145 additions & 0 deletions
145
src/test/kotlin/com/example/backendcart/controller/CartControllerTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package com.example.backendcart.controller | ||
|
||
import com.example.backendcart.model.Cart | ||
import com.example.backendcart.repository.CartRepository | ||
import com.example.backendcart.service.CartService | ||
import org.junit.jupiter.api.Test | ||
import org.mockito.Mockito.doReturn | ||
import org.mockito.Mockito.mock | ||
import org.springframework.http.server.reactive.ServerHttpResponse | ||
import reactor.core.publisher.Flux | ||
import reactor.core.publisher.Mono | ||
import reactor.test.StepVerifier | ||
|
||
class CartControllerTest { | ||
private val response = mock(ServerHttpResponse::class.java) | ||
private val cartRepository = mock(CartRepository::class.java) | ||
private val cartService = CartService(cartRepository) | ||
private val cartController = CartController(cartService) | ||
private val cart = Cart( | ||
userId = "User ID", | ||
productId = "Product ID", | ||
quantity = 2 | ||
) | ||
@Test | ||
fun `should add product in cart if it is not present in cart`() { | ||
doReturn(Mono.just(cart)) | ||
.`when`(cartRepository) | ||
.insert(cart) | ||
StepVerifier.create(cartController.addProductInCart(cart, response)) | ||
.expectNext("Product added to cart") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should not add product in cart if it is present in cart`() { | ||
doReturn(Mono.error<Exception>(Exception("Product already exist in cart"))) | ||
.`when`(cartRepository) | ||
.insert(cart) | ||
StepVerifier.create(cartController.addProductInCart(cart, response)) | ||
.expectNext("Product already exist in cart") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should get product quantity if product available in cart`() { | ||
doReturn(Mono.just(cart)) | ||
.`when`(cartRepository) | ||
.findByUserIdAndProductId(cart.userId, cart.productId) | ||
StepVerifier.create(cartController.getProductQuantityInCart(cart.productId, cart.userId)) | ||
.expectNext(cart.quantity) | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should get product quantity as 0 if product is not available in cart`() { | ||
doReturn(Mono.empty<Cart>()) | ||
.`when`(cartRepository) | ||
.findByUserIdAndProductId(cart.userId, cart.productId) | ||
StepVerifier.create(cartController.getProductQuantityInCart(cart.productId, cart.userId)) | ||
.expectNext(0) | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should get productId present in user cart`() { | ||
doReturn(Flux.just(cart)) | ||
.`when`(cartRepository) | ||
.findByUserId(cart.userId) | ||
StepVerifier.create(cartController.getUserCart(cart.userId)) | ||
.expectNext(cart.productId) | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should update product quantity when it is available in cart`() { | ||
val newCart = Cart( | ||
userId = cart.userId, | ||
productId = cart.productId, | ||
quantity = 20 | ||
) | ||
doReturn(Mono.just(true)) | ||
.`when`(cartRepository) | ||
.existsByUserIdAndProductId(cart.userId, cart.productId) | ||
doReturn(Mono.empty<Cart>()) | ||
.`when`(cartRepository) | ||
.deleteByUserIdAndProductId(cart.userId, cart.productId) | ||
doReturn(Mono.just(newCart)) | ||
.`when`(cartRepository) | ||
.insert(newCart) | ||
StepVerifier.create(cartController.updateProductQuantity(newCart, response)) | ||
.expectNext("Product quantity updated") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should not update product quantity when it is not available in cart`() { | ||
val newCart = Cart( | ||
userId = cart.userId, | ||
productId = cart.productId, | ||
quantity = 20 | ||
) | ||
doReturn(Mono.just(false)) | ||
.`when`(cartRepository) | ||
.existsByUserIdAndProductId(cart.userId, cart.productId) | ||
StepVerifier.create(cartController.updateProductQuantity(newCart, response)) | ||
.expectNext("Product not found") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should delete product from cart when it is available in cart`() { | ||
doReturn(Mono.just(true)) | ||
.`when`(cartRepository) | ||
.existsByUserIdAndProductId(cart.userId, cart.productId) | ||
doReturn(Mono.empty<Void>()) | ||
.`when`(cartRepository) | ||
.deleteByUserIdAndProductId(cart.userId, cart.productId) | ||
StepVerifier.create(cartController.deleteProductFromCart(cart.productId, cart.userId, response)) | ||
.expectNext("Product removed from cart") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should not delete product from cart when it is not available in cart`() { | ||
doReturn(Mono.just(false)) | ||
.`when`(cartRepository) | ||
.existsByUserIdAndProductId(cart.userId, cart.productId) | ||
StepVerifier.create(cartController.deleteProductFromCart(cart.productId, cart.userId, response)) | ||
.expectNext("Product not found in cart") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should empty cart when products are available in cart`() { | ||
doReturn(Mono.just(true)) | ||
.`when`(cartRepository) | ||
.existsByUserId(cart.userId) | ||
doReturn(Flux.empty<Void>()) | ||
.`when`(cartRepository) | ||
.deleteByUserId(cart.userId) | ||
StepVerifier.create(cartController.emptyCart(cart.userId, response)) | ||
.expectNext("Successful") | ||
.verifyComplete() | ||
} | ||
@Test | ||
fun `should not empty cart when products are not available in cart`() { | ||
doReturn(Mono.just(false)) | ||
.`when`(cartRepository) | ||
.existsByUserId(cart.userId) | ||
StepVerifier.create(cartController.emptyCart(cart.userId, response)) | ||
.expectNext("Cart not found") | ||
.verifyComplete() | ||
} | ||
} |