From e0b1ead680ef0343ea2cf960cbb763f91d7e2c12 Mon Sep 17 00:00:00 2001 From: Faishal Nelwan <108632813+pesolosep@users.noreply.github.com> Date: Thu, 23 May 2024 20:16:42 +0700 Subject: [PATCH 1/3] [REFACTOR] [GREEN] FIX ALL POSTMAN WORKS, IMPLEMENT TESTS TOO BABY --- build.gradle.kts | 1 + .../controller/SubscriptionBoxController.java | 60 +++--- .../dto/DTOMapper.java | 68 ++++-- .../dto/ItemDTO.java | 14 ++ .../dto/SubscriptionBoxDTO.java | 15 +- .../model/Item.java | 11 + .../model/SubscriptionBox.java | 16 +- .../repository/SubscriptionBoxRepository.java | 61 +----- .../service/SubscriptionBoxService.java | 13 +- .../service/SubscriptionBoxServiceImpl.java | 107 +++++----- .../SubscriptionBoxControllerTest.java | 200 ++++++++++++++---- .../factory/SubscriptionBoxFactoryTest.java | 4 +- .../SubscriptionBoxServiceImplTest.java | 80 ------- 13 files changed, 353 insertions(+), 297 deletions(-) create mode 100644 src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/ItemDTO.java diff --git a/build.gradle.kts b/build.gradle.kts index a02ee00..67dd0f3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -23,6 +23,7 @@ repositories { } dependencies { + implementation("org.springframework.boot:spring-boot-starter-logging") 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") diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java index 725c95b..2e7d9e6 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java @@ -1,5 +1,8 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.controller; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.DTOMapper; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.SubscriptionBoxDTO; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.service.SubscriptionBoxService; import org.springframework.beans.factory.annotation.Autowired; @@ -13,10 +16,11 @@ @RestController @RequestMapping("/subscription-box") -@CrossOrigin(origins = "http://localhost:3000") // Change to specific origin if needed +@CrossOrigin(origins = "*") // Change to specific origin if needed public class SubscriptionBoxController { private final SubscriptionBoxService subscriptionBoxService; + private static final Logger logger = LoggerFactory.getLogger(SubscriptionBoxController.class); @Autowired public SubscriptionBoxController(SubscriptionBoxService subscriptionBoxService) { @@ -24,20 +28,39 @@ public SubscriptionBoxController(SubscriptionBoxService subscriptionBoxService) } @PostMapping("/create") - public CompletableFuture> createSubscriptionBox(@RequestBody SubscriptionBox subscriptionBox) { + public CompletableFuture> createSubscriptionBox(@RequestBody SubscriptionBoxDTO subscriptionBoxDTO) { + SubscriptionBox subscriptionBox = DTOMapper.convertDTOtoModel(subscriptionBoxDTO); return subscriptionBoxService.save(subscriptionBox) .thenApply(ResponseEntity::ok) .exceptionally(ex -> ResponseEntity.badRequest().build()); } + @GetMapping("/list") public CompletableFuture>> findAll() { return subscriptionBoxService.findAll() .thenApply(ResponseEntity::ok); } + @PatchMapping("/update") + public CompletableFuture> updateSubscriptionBox(@RequestBody SubscriptionBoxDTO subscriptionBoxDTO) { + if (subscriptionBoxDTO.getId() == null || subscriptionBoxDTO.getId().isEmpty()) { + return CompletableFuture.completedFuture(ResponseEntity.badRequest().build()); + } + + return subscriptionBoxService.findById(subscriptionBoxDTO.getId()) + .thenCompose(optionalSubscriptionBox -> { + if (optionalSubscriptionBox.isEmpty()) { + return CompletableFuture.completedFuture(ResponseEntity.notFound().build()); + } else { + return subscriptionBoxService.update(subscriptionBoxDTO) + .thenApply(ResponseEntity::ok); + } + }); + } + @GetMapping("/{id}") - public CompletableFuture> findById(@PathVariable String id) { + public CompletableFuture> findById(@PathVariable String id) { try { UUID.fromString(id); } catch (IllegalArgumentException e) { @@ -50,22 +73,6 @@ public CompletableFuture> findById(@PathVariable .orElse(ResponseEntity.notFound().build())); } - @PatchMapping("/update") - public CompletableFuture> updateSubscriptionBox(@RequestBody SubscriptionBox subscriptionBox) { - if (subscriptionBox.getId() == null || subscriptionBox.getId().isEmpty()) { - return CompletableFuture.completedFuture(ResponseEntity.badRequest().build()); - } - - return subscriptionBoxService.findById(subscriptionBox.getId()) - .thenCompose(optionalSubscriptionBox -> { - if (optionalSubscriptionBox.isEmpty()) { - return CompletableFuture.completedFuture(ResponseEntity.notFound().build()); - } else { - return subscriptionBoxService.update(subscriptionBox) - .thenApply(ResponseEntity::ok); - } - }); - } @DeleteMapping("/{id}") public CompletableFuture> deleteSubscriptionBox(@PathVariable String id) { @@ -81,25 +88,28 @@ public CompletableFuture> deleteSubscriptionBox(@PathVari } @GetMapping("/price/less-than/{price}") - public CompletableFuture>> findByPriceLessThan(@PathVariable int price) { + public CompletableFuture>> findByPriceLessThan(@PathVariable int price) { return subscriptionBoxService.findByPriceLessThan(price) .thenApply(ResponseEntity::ok); } @GetMapping("/price/greater-than/{price}") - public CompletableFuture>> findByPriceGreaterThan(@PathVariable int price) { + public CompletableFuture>> findByPriceGreaterThan(@PathVariable int price) { return subscriptionBoxService.findByPriceGreaterThan(price) .thenApply(ResponseEntity::ok); } @GetMapping("/price/equals/{price}") - public CompletableFuture>> findByPriceEquals(@PathVariable int price) { + public CompletableFuture>> findByPriceEquals(@PathVariable int price) { return subscriptionBoxService.findByPriceEquals(price) .thenApply(ResponseEntity::ok); } - @GetMapping("/name/{name}") - public CompletableFuture>>> findByName(@PathVariable String name) { + @GetMapping("/name/{nameURL}") + public CompletableFuture>>> findByName(@PathVariable String nameURL) { +// logger.info("Searching for SubscriptionBox with name before split: {}", nameURL); + String name = nameURL.replaceAll("-", " "); +// logger.info("Searching for SubscriptionBox with name: {}", name); return subscriptionBoxService.findByName(name) .thenApply(ResponseEntity::ok); } diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java index 710e0e6..b66597a 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java @@ -1,39 +1,79 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; -import org.springframework.stereotype.Component; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.factory.SubscriptionBoxFactory; +import org.springframework.stereotype.Component; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Component public class DTOMapper { - public static SubscriptionBoxDTO convertModeltoDto (SubscriptionBox subscriptionBox){ + public static SubscriptionBoxDTO convertModelToDto(SubscriptionBox subscriptionBox) { + List itemDTOs = Optional.ofNullable(subscriptionBox.getItems()) + .map(items -> items.stream() + .map(DTOMapper::convertItemToDto) + .collect(Collectors.toList())) + .orElse(null); + return new SubscriptionBoxDTO( subscriptionBox.getId(), subscriptionBox.getName(), subscriptionBox.getType(), subscriptionBox.getPrice(), - subscriptionBox.getItems() + itemDTOs ); } - public static SubscriptionBox convertDTOtoModel(SubscriptionBoxDTO subscriptionBoxDTO){ - String id = subscriptionBoxDTO.getId(); - String name = subscriptionBoxDTO.getName(); - String type = subscriptionBoxDTO.getType(); - int price = subscriptionBoxDTO.getPrice(); - List items = subscriptionBoxDTO.getItems(); - return new SubscriptionBoxFactory().create(id,name,type,price,items); + public static SubscriptionBox convertDTOtoModel(SubscriptionBoxDTO subscriptionBoxDTO) { + List items = Optional.ofNullable(subscriptionBoxDTO.getItems()).map(dtoItems -> + dtoItems.stream() + .map(DTOMapper::convertDtoToItem) + .collect(Collectors.toList()) + ).orElse(null); + + return new SubscriptionBoxFactory().create( + subscriptionBoxDTO.getId(), + subscriptionBoxDTO.getName(), + subscriptionBoxDTO.getType(), + subscriptionBoxDTO.getPrice(), + items + ); } - public static SubscriptionBox updateSubscriptionBox(SubscriptionBox subscriptionBox, SubscriptionBoxDTO subscriptionBoxDTO){ - Optional.ofNullable(subscriptionBoxDTO.getItems()).ifPresent(subscriptionBox::setItems); - Optional.of( - subscriptionBoxDTO.getPrice()).ifPresent(subscriptionBox::setPrice); + public static SubscriptionBox updateSubscriptionBox(SubscriptionBox subscriptionBox, SubscriptionBoxDTO subscriptionBoxDTO) { + Optional.ofNullable(subscriptionBoxDTO.getItems()).ifPresent(dtoItems -> { + List items = dtoItems.stream() + .map(DTOMapper::convertDtoToItem) + .collect(Collectors.toList()); + subscriptionBox.setItems(items); + }); + Optional.of(subscriptionBoxDTO.getPrice()).ifPresent(subscriptionBox::setPrice); return subscriptionBox; + } + + public static ItemDTO convertItemToDto(Item item) { + return new ItemDTO( + item.getId(), + item.getName(), + item.getQuantity() + ); + } + + public static Item convertDtoToItem(ItemDTO itemDTO) { + return new Item( + itemDTO.getId(), + itemDTO.getName(), + itemDTO.getQuantity() + ); + } + public static Item updateItem(Item item, ItemDTO itemDTO) { + Optional.ofNullable(itemDTO.getId()).ifPresent(item::setId); + Optional.ofNullable(itemDTO.getName()).ifPresent(item::setName); + Optional.of(itemDTO.getQuantity()).ifPresent(item::setQuantity); + return item; } } diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/ItemDTO.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/ItemDTO.java new file mode 100644 index 0000000..629e890 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/ItemDTO.java @@ -0,0 +1,14 @@ +package id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto; + +import lombok.*; + + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class ItemDTO { + private String id; + private String name; + private int quantity; +} \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java index e608fb1..88ae987 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java @@ -7,11 +7,12 @@ @AllArgsConstructor @NoArgsConstructor -@Getter @Setter +@Getter +@Setter public class SubscriptionBoxDTO { - String id; - String name; - String type; - int price; - List items; -} + private String id; + private String name; + private String type; + private int price; + private List items; +} \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/Item.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/Item.java index d2b73c6..b83498d 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/Item.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/Item.java @@ -1,5 +1,6 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.model; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -19,5 +20,15 @@ public class Item { private int quantity; @ManyToMany(mappedBy = "items") + @JsonBackReference private List subscriptionBoxes; + + public Item(String id, String name, int quantity) { + this.id = id; + this.name = name; + this.quantity = quantity; + } + + public Item() { + } } \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java index 27b9af7..507530b 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java @@ -1,6 +1,7 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.model; +import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; @@ -30,6 +31,7 @@ public class SubscriptionBox { joinColumns = @JoinColumn(name = "subscriptionbox_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "item_id", referencedColumnName = "id") ) + @JsonManagedReference List items; // Rating rating; @@ -39,7 +41,7 @@ public SubscriptionBox(){ public SubscriptionBox( String name, String type, int price, List items){ this.id = UUID.randomUUID().toString(); - this.name = name; + this.setName(name); this.setType(type); this.setPrice(price); this.items = items; @@ -50,7 +52,7 @@ public void setType(String type) { type.equalsIgnoreCase("quarterly") | type.equalsIgnoreCase("semi-annual") ){ - this.type = type; + this.type = type.toUpperCase(); } else{ throw new IllegalArgumentException("Invalid type"); @@ -58,7 +60,17 @@ public void setType(String type) { } + public void setName(String name) { + if (!name.contains("-") + ){ + this.name = name; + } + else{ + throw new IllegalArgumentException("Do not put '-' inside your name!"); + } + + } public void setPrice(int price) { if (price >0){ this.price = price; diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java index b45df42..6787b2e 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java @@ -30,9 +30,10 @@ public SubscriptionBox save(SubscriptionBox subscriptionBox) { @Transactional public Optional findById(String id){ - SubscriptionBox subscription = entityManager.find(SubscriptionBox.class, id); - return Optional.ofNullable(subscription); + SubscriptionBox subscriptionBox = entityManager.find(SubscriptionBox.class, id); + return Optional.ofNullable(subscriptionBox); } + @Transactional public List findAll(){ String jpql = "SELECT sb FROM SubscriptionBox sb"; @@ -93,59 +94,5 @@ public Optional> findDistinctNames() { return Optional.ofNullable(result.isEmpty() ? null : result); } -// private List subscriptionBoxes = new ArrayList<>(); -// private List filteredBoxesByPrice = new ArrayList<>(); -//// private List filteredBoxesByRating = new ArrayList<>(); -// -// public SubscriptionBox addBox(SubscriptionBox box) { -// subscriptionBoxes.add(box); -// return box; -// } -// -// public SubscriptionBox deleteBox(String id) { -// for (SubscriptionBox subscriptionBox : subscriptionBoxes) { -// if (subscriptionBox.getId().equals(id)) { -// subscriptionBoxes.remove(subscriptionBox); -// return subscriptionBox; -// } -// } -// return null; -// } -// -// public SubscriptionBox editBox(String id, SubscriptionBox updatedBox) { -// for (SubscriptionBox box : subscriptionBoxes) { -// if (box.getId().equals(id)) { -// // Assuming the updatedBox object contains the updated fields -// box.setName(updatedBox.getName()); -// box.setPrice(updatedBox.getPrice()); -// return box; // Return the updated box -// } -// } -// return null; // Return null if no box with the given id was found -// } -// -// -// public List viewAll() { -// return subscriptionBoxes; -// } -// -// public String viewDetails(String boxId) { -// for (SubscriptionBox subscriptionBox : subscriptionBoxes) { -// if (subscriptionBox.getId().equals(boxId)) { -// return subscriptionBox.getName(); -// } -// } -// return null; -// } -// -// public List filterByPrice(int price) { -// List filteredBoxes = new ArrayList<>(); -// for (SubscriptionBox subscriptionBox : subscriptionBoxes) { -// if (subscriptionBox.getPrice() == price) { -// filteredBoxes.add(subscriptionBox); -// } -// } -// filteredBoxesByPrice = filteredBoxes; -// return filteredBoxesByPrice; -// } + } \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java index a8c52c7..9506c19 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java @@ -2,6 +2,7 @@ import java.util.List; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.SubscriptionBoxDTO; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import org.springframework.scheduling.annotation.Async; @@ -11,21 +12,21 @@ public interface SubscriptionBoxService { CompletableFuture save(SubscriptionBox subscriptionBox); - CompletableFuture> findById(String id); + CompletableFuture> findById(String id); CompletableFuture> findAll(); - CompletableFuture update(SubscriptionBox subscriptionBox); + CompletableFuture update(SubscriptionBoxDTO subscriptionBoxDTO); CompletableFuture delete(String id); - CompletableFuture> findByPriceLessThan(int price); + CompletableFuture> findByPriceLessThan(int price); - CompletableFuture> findByPriceGreaterThan(int price); + CompletableFuture> findByPriceGreaterThan(int price); - CompletableFuture> findByPriceEquals(int price); + CompletableFuture> findByPriceEquals(int price); - CompletableFuture>> findByName(String name); + CompletableFuture>> findByName(String name); CompletableFuture>> findDistinctNames(); diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java index 1c64846..5e3960a 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java @@ -5,7 +5,10 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.SubscriptionBoxDTO; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.DTOMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -26,11 +29,15 @@ public CompletableFuture save(SubscriptionBox subscriptionBox) @Override @Async - public CompletableFuture> findById(String id) { + public CompletableFuture> findById(String id) { if (id == null || id.isEmpty()) { throw new IllegalArgumentException("ID cannot be null or empty"); } - return CompletableFuture.completedFuture(subscriptionBoxRepository.findById(id)); + + return subscriptionBoxRepository.findById(id) + .map(subscriptionBox -> CompletableFuture.completedFuture(Optional.of(DTOMapper.convertModelToDto(subscriptionBox)))) + .orElse(CompletableFuture.completedFuture(Optional.empty())); +// } @Override @@ -42,21 +49,32 @@ public CompletableFuture> findAll() { @Override @Async - public CompletableFuture update(SubscriptionBox subscriptionBox) { - if (subscriptionBox == null) { - throw new IllegalArgumentException("SubscriptionBox cannot be null"); + public CompletableFuture update(SubscriptionBoxDTO subscriptionBoxDTO) { +// if (subscriptionBox == null) { +// throw new IllegalArgumentException("SubscriptionBox cannot be null"); +// } +// return CompletableFuture.completedFuture(subscriptionBoxRepository.update(subscriptionBox)); + if (subscriptionBoxDTO == null) { + throw new IllegalArgumentException("Subscription cannot be null"); } - return CompletableFuture.completedFuture(subscriptionBoxRepository.update(subscriptionBox)); + + return subscriptionBoxRepository.findById(subscriptionBoxDTO.getId()) + .map(subscriptionBox -> { + DTOMapper.updateSubscriptionBox(subscriptionBox, subscriptionBoxDTO); + return CompletableFuture.completedFuture(subscriptionBoxRepository.update(subscriptionBox)); + }) + .orElseThrow(() -> new IllegalArgumentException("Subscription isn't found")); + } @Override @Async public CompletableFuture delete(String id) { if (id == null || id.isEmpty()) { - throw new IllegalArgumentException("ID cannot be null or empty"); + return CompletableFuture.failedFuture(new IllegalArgumentException("ID cannot be null or empty")); } - Optional subscriptionBox = subscriptionBoxRepository.findById(id); - if (!subscriptionBox.isPresent()) { + + if (subscriptionBoxRepository.findById(id).isEmpty()) { throw new IllegalArgumentException("Subscription Box not found"); } subscriptionBoxRepository.delete(id); @@ -65,32 +83,45 @@ public CompletableFuture delete(String id) { @Override @Async - public CompletableFuture> findByPriceLessThan(int price) { + public CompletableFuture> findByPriceLessThan(int price) { List result = subscriptionBoxRepository.findByPriceLessThan(price); - return CompletableFuture.completedFuture(result); + List dtoResult = result.stream() + .map(DTOMapper::convertModelToDto) + .collect(Collectors.toList()); + return CompletableFuture.completedFuture(dtoResult); } @Override @Async - public CompletableFuture> findByPriceGreaterThan(int price) { + public CompletableFuture> findByPriceGreaterThan(int price) { List result = subscriptionBoxRepository.findByPriceGreaterThan(price); - return CompletableFuture.completedFuture(result); + List dtoResult = result.stream() + .map(DTOMapper::convertModelToDto) + .collect(Collectors.toList()); + return CompletableFuture.completedFuture(dtoResult); } @Override @Async - public CompletableFuture> findByPriceEquals(int price) { + public CompletableFuture> findByPriceEquals(int price) { List result = subscriptionBoxRepository.findByPriceEquals(price); - return CompletableFuture.completedFuture(result); + List dtoResult = result.stream() + .map(DTOMapper::convertModelToDto) + .collect(Collectors.toList()); + return CompletableFuture.completedFuture(dtoResult); } @Override @Async - public CompletableFuture>> findByName(String name) { + public CompletableFuture>> findByName(String name) { Optional> result = subscriptionBoxRepository.findByName(name); - return CompletableFuture.completedFuture(result); + Optional> dtoResult = result.map(list -> list.stream() + .map(DTOMapper::convertModelToDto) + .collect(Collectors.toList())); + return CompletableFuture.completedFuture(dtoResult); } + @Override public CompletableFuture>> findDistinctNames() { Optional> distinctNames = subscriptionBoxRepository.findDistinctNames(); @@ -100,45 +131,3 @@ public CompletableFuture>> findDistinctNames() { } -// -//@Service -//public class SubscriptionBoxServiceImpl implements SubscriptionBoxService{ -// @Autowired -// private SubscriptionBoxRepository subscriptionBoxRepository; -// -// @Override -// @Async -// public CompletableFuture -// -// @Override -// public SubscriptionBox addBox(SubscriptionBox box) { -// return subscriptionBoxRepository.addBox(box); -// } -// -// @Override -// public SubscriptionBox deleteBox(String id) { -// return subscriptionBoxRepository.deleteBox(id); -// } -// -// @Override -// public SubscriptionBox editBox(String id, SubscriptionBox box) { -// return subscriptionBoxRepository.editBox(id, box); -// } -// -// @Override -// public List viewAll() { -// return subscriptionBoxRepository.viewAll(); -// } -// -// @Override -// public String viewDetails(String boxId) { -// return subscriptionBoxRepository.viewDetails(boxId); -// } -// -// @Override -// public List filterByPrice(int price) { -// return subscriptionBoxRepository.filterByPrice(price); -// } -// -// -//} \ No newline at end of file diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java index 303cc0a..12e1932 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java @@ -1,5 +1,8 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.controller; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.DTOMapper; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.SubscriptionBoxDTO; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.service.SubscriptionBoxService; import org.junit.jupiter.api.BeforeEach; @@ -9,10 +12,7 @@ import org.mockito.MockitoAnnotations; import org.springframework.http.ResponseEntity; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import static org.junit.jupiter.api.Assertions.*; @@ -28,21 +28,31 @@ class SubscriptionBoxControllerTest { private SubscriptionBoxController subscriptionBoxController; private SubscriptionBox subscriptionBox; + private SubscriptionBoxDTO subscriptionBoxDTO; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); - subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + // Create items + Item item1 = new Item("1", "Item 1", 10); + Item item2 = new Item("2", "Item 2", 20); + List items = Arrays.asList(item1, item2); + + // Create subscription box with items + subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, items); subscriptionBox.setId(UUID.randomUUID().toString()); + + // Convert to DTO + subscriptionBoxDTO = DTOMapper.convertModelToDto(subscriptionBox); } @Test - void testCreateSubscriptionBox() { + void testCreateSubscriptionBox_HappyPath() { when(subscriptionBoxService.save(any(SubscriptionBox.class))) .thenReturn(CompletableFuture.completedFuture(subscriptionBox)); - CompletableFuture> result = subscriptionBoxController.createSubscriptionBox(subscriptionBox); + CompletableFuture> result = subscriptionBoxController.createSubscriptionBox(subscriptionBoxDTO); assertNotNull(result); assertTrue(result.isDone()); @@ -50,8 +60,20 @@ void testCreateSubscriptionBox() { } @Test - void testFindAll() { - List subscriptionBoxes = Arrays.asList(subscriptionBox); + void testCreateSubscriptionBox_UnhappyPath() { + when(subscriptionBoxService.save(any(SubscriptionBox.class))) + .thenReturn(CompletableFuture.failedFuture(new RuntimeException("Error saving subscription box"))); + + CompletableFuture> result = subscriptionBoxController.createSubscriptionBox(subscriptionBoxDTO); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.badRequest().build(), result.join()); + } + + @Test + void testFindAll_HappyPath() { + List subscriptionBoxes = Collections.singletonList(subscriptionBox); when(subscriptionBoxService.findAll()) .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); @@ -63,12 +85,15 @@ void testFindAll() { assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); } + @Test - void testFindById() { - when(subscriptionBoxService.findById(subscriptionBox.getId())) - .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBox))); + void testUpdateSubscriptionBox_HappyPath() { + when(subscriptionBoxService.findById(subscriptionBoxDTO.getId())) + .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBoxDTO))); + when(subscriptionBoxService.update(any(SubscriptionBoxDTO.class))) + .thenReturn(CompletableFuture.completedFuture(subscriptionBox)); - CompletableFuture> result = subscriptionBoxController.findById(subscriptionBox.getId()); + CompletableFuture> result = subscriptionBoxController.updateSubscriptionBox(subscriptionBoxDTO); assertNotNull(result); assertTrue(result.isDone()); @@ -76,10 +101,10 @@ void testFindById() { } @Test - void testFindByIdInvalidId() { - String invalidId = "invalid_id"; + void testUpdateSubscriptionBox_UnhappyPath() { + subscriptionBoxDTO.setId(null); - CompletableFuture> result = subscriptionBoxController.findById(invalidId); + CompletableFuture> result = subscriptionBoxController.updateSubscriptionBox(subscriptionBoxDTO); assertNotNull(result); assertTrue(result.isDone()); @@ -87,21 +112,41 @@ void testFindByIdInvalidId() { } @Test - void testUpdateSubscriptionBox() { + void testUpdateSubscriptionBox_NotFound() { + when(subscriptionBoxService.findById(subscriptionBoxDTO.getId())) + .thenReturn(CompletableFuture.completedFuture(Optional.empty())); + + CompletableFuture> result = subscriptionBoxController.updateSubscriptionBox(subscriptionBoxDTO); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.notFound().build(), result.join()); + } + + @Test + void testFindById_HappyPath() { when(subscriptionBoxService.findById(subscriptionBox.getId())) - .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBox))); - when(subscriptionBoxService.update(any(SubscriptionBox.class))) - .thenReturn(CompletableFuture.completedFuture(subscriptionBox)); + .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBoxDTO))); - CompletableFuture> result = subscriptionBoxController.updateSubscriptionBox(subscriptionBox); + CompletableFuture> result = subscriptionBoxController.findById(subscriptionBox.getId()); assertNotNull(result); assertTrue(result.isDone()); - assertEquals(ResponseEntity.ok(subscriptionBox), result.join()); + assertEquals(ResponseEntity.ok(subscriptionBoxDTO), result.join()); + } + + @Test + void testFindById_UnhappyPath() { + String invalidId = "invalid-uuid"; + CompletableFuture> result = subscriptionBoxController.findById(invalidId); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.badRequest().build(), result.join()); } @Test - void testDeleteSubscriptionBox() { + void testDeleteSubscriptionBox_HappyPath() { when(subscriptionBoxService.delete(subscriptionBox.getId())) .thenReturn(CompletableFuture.completedFuture(null)); @@ -113,63 +158,117 @@ void testDeleteSubscriptionBox() { } @Test - void testFindByPriceLessThan() { - List subscriptionBoxes = Arrays.asList(subscriptionBox); + void testDeleteSubscriptionBox_UnhappyPath() { + CompletableFuture> expectedResult = CompletableFuture.completedFuture(ResponseEntity.badRequest().build()); + CompletableFuture> result = subscriptionBoxController.deleteSubscriptionBox("invalid_id"); + + assertTrue(result.isDone()); + assertEquals(expectedResult.join(), result.join()); + } + + + @Test + void testFindByPriceLessThan_HappyPath() { + List expectedDTOs = Collections.singletonList(subscriptionBoxDTO); when(subscriptionBoxService.findByPriceLessThan(150)) - .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + .thenReturn(CompletableFuture.completedFuture(expectedDTOs)); - CompletableFuture>> result = subscriptionBoxController.findByPriceLessThan(150); + CompletableFuture>> result = subscriptionBoxController.findByPriceLessThan(150); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(expectedDTOs), result.join()); + } + + @Test + void testFindByPriceLessThan_UnhappyPath() { + when(subscriptionBoxService.findByPriceLessThan(150)) + .thenReturn(CompletableFuture.failedFuture(new RuntimeException("Error finding by price less than"))); + + CompletableFuture>> result = subscriptionBoxController.findByPriceLessThan(150); assertNotNull(result); assertTrue(result.isDone()); - assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); } @Test - void testFindByPriceGreaterThan() { - List subscriptionBoxes = Arrays.asList(subscriptionBox); + void testFindByPriceGreaterThan_HappyPath() { + List expectedDTOs = Collections.singletonList(subscriptionBoxDTO); + when(subscriptionBoxService.findByPriceGreaterThan(50)) + .thenReturn(CompletableFuture.completedFuture(expectedDTOs)); + + CompletableFuture>> result = subscriptionBoxController.findByPriceGreaterThan(50); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(expectedDTOs), result.join()); + } + @Test + void testFindByPriceGreaterThan_UnhappyPath() { when(subscriptionBoxService.findByPriceGreaterThan(50)) - .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + .thenReturn(CompletableFuture.failedFuture(new RuntimeException("Error finding by price greater than"))); - CompletableFuture>> result = subscriptionBoxController.findByPriceGreaterThan(50); + CompletableFuture>> result = subscriptionBoxController.findByPriceGreaterThan(50); assertNotNull(result); assertTrue(result.isDone()); - assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); } @Test - void testFindByPriceEquals() { - List subscriptionBoxes = Arrays.asList(subscriptionBox); + void testFindByPriceEquals_HappyPath() { + List expectedDTOs = Collections.singletonList(subscriptionBoxDTO); + when(subscriptionBoxService.findByPriceEquals(100)) + .thenReturn(CompletableFuture.completedFuture(expectedDTOs)); + + CompletableFuture>> result = subscriptionBoxController.findByPriceEquals(100); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(expectedDTOs), result.join()); + } + @Test + void testFindByPriceEquals_UnhappyPath() { when(subscriptionBoxService.findByPriceEquals(100)) - .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + .thenReturn(CompletableFuture.failedFuture(new RuntimeException("Error finding by price equals"))); - CompletableFuture>> result = subscriptionBoxController.findByPriceEquals(100); + CompletableFuture>> result = subscriptionBoxController.findByPriceEquals(100); assertNotNull(result); assertTrue(result.isDone()); - assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); + } @Test - void testFindByName() { - List subscriptionBoxes = Arrays.asList(subscriptionBox); + void testFindByName_HappyPath() { + List expectedDTOs = Collections.singletonList(subscriptionBoxDTO); + String nameURL = "Basic".replaceAll(" ", "-"); + when(subscriptionBoxService.findByName(subscriptionBox.getName())) + .thenReturn(CompletableFuture.completedFuture(Optional.of(expectedDTOs))); + + CompletableFuture>>> result = subscriptionBoxController.findByName(nameURL); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(Optional.of(expectedDTOs)), result.join()); + } - when(subscriptionBoxService.findByName("Basic")) - .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBoxes))); + @Test + void testFindByName_UnhappyPath() { + String nameURL = "Basic".replaceAll(" ", "-"); + when(subscriptionBoxService.findByName(subscriptionBox.getName())) + .thenReturn(CompletableFuture.failedFuture(new RuntimeException("Error finding by name"))); - CompletableFuture>>> result = subscriptionBoxController.findByName("Basic"); + CompletableFuture>>> result = subscriptionBoxController.findByName(nameURL); assertNotNull(result); assertTrue(result.isDone()); - assertEquals(ResponseEntity.ok(Optional.of(subscriptionBoxes)), result.join()); } @Test - void testFindDistinctNames() { + void testFindDistinctNames_HappyPath() { List names = Arrays.asList("Basic", "Premium"); when(subscriptionBoxService.findDistinctNames()) @@ -181,4 +280,15 @@ void testFindDistinctNames() { assertTrue(result.isDone()); assertEquals(ResponseEntity.ok(Optional.of(names)), result.join()); } + + @Test + void testFindDistinctNames_UnhappyPath() { + when(subscriptionBoxService.findDistinctNames()) + .thenReturn(CompletableFuture.failedFuture(new RuntimeException("Error finding distinct names"))); + + CompletableFuture>>> result = subscriptionBoxController.findDistinctNames(); + + assertNotNull(result); + assertTrue(result.isDone()); + } } diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java index a8bea7e..cefeef3 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java @@ -28,10 +28,10 @@ void testCreateSubscriptionBoxWithParameters() { items.add(new Item()); // Assuming you have a constructor in Item class like this items.add(new Item()); - SubscriptionBox subscriptionBox = subscriptionBoxFactory.create("1", "Deluxe Box", "Monthly", 150, items); + SubscriptionBox subscriptionBox = subscriptionBoxFactory.create("1", "Deluxe Box", "MONTHLY", 150, items); assertEquals("Deluxe Box", subscriptionBox.getName()); - assertEquals("Monthly", subscriptionBox.getType()); + assertEquals("MONTHLY", subscriptionBox.getType()); assertEquals(150, subscriptionBox.getPrice()); assertNotNull(subscriptionBox.getItems()); assertEquals(2, subscriptionBox.getItems().size()); // Check that two items were added diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java index aa05b32..f1934ea 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java @@ -46,17 +46,6 @@ void testSave() throws ExecutionException, InterruptedException { verify(subscriptionBoxRepository, times(1)).save(subscriptionBox); } - @Test - void testFindById() throws ExecutionException, InterruptedException { - when(subscriptionBoxRepository.findById("1")).thenReturn(Optional.of(subscriptionBox)); - - CompletableFuture> future = subscriptionBoxService.findById("1"); - Optional result = future.get(); - - assertTrue(result.isPresent()); - assertEquals(subscriptionBox, result.get()); - verify(subscriptionBoxRepository, times(1)).findById("1"); - } @Test void testFindByIdInvalidId() { @@ -79,16 +68,6 @@ void testFindAll() throws ExecutionException, InterruptedException { verify(subscriptionBoxRepository, times(1)).findAll(); } - @Test - void testUpdate() throws ExecutionException, InterruptedException { - when(subscriptionBoxRepository.update(subscriptionBox)).thenReturn(subscriptionBox); - - CompletableFuture future = subscriptionBoxService.update(subscriptionBox); - SubscriptionBox result = future.get(); - - assertEquals(subscriptionBox, result); - verify(subscriptionBoxRepository, times(1)).update(subscriptionBox); - } @Test void testUpdateInvalidBox() { @@ -110,14 +89,6 @@ void testDelete() throws ExecutionException, InterruptedException { verify(subscriptionBoxRepository, times(1)).delete("1"); } - @Test - void testDeleteInvalidId() { - assertThrows(IllegalArgumentException.class, () -> { - subscriptionBoxService.delete("").get(); - }); - verify(subscriptionBoxRepository, never()).delete(anyString()); - } - @Test void testDeleteSubscriptionNotFound() { when(subscriptionBoxRepository.findById("1")).thenReturn(Optional.empty()); @@ -130,58 +101,7 @@ void testDeleteSubscriptionNotFound() { verify(subscriptionBoxRepository, never()).delete(anyString()); } - @Test - void testFindByPriceLessThan() throws ExecutionException, InterruptedException { - List subscriptionBoxes = Arrays.asList(subscriptionBox); - when(subscriptionBoxRepository.findByPriceLessThan(150)).thenReturn(subscriptionBoxes); - - CompletableFuture> future = subscriptionBoxService.findByPriceLessThan(150); - List result = future.get(); - assertEquals(1, result.size()); - assertEquals(subscriptionBox, result.get(0)); - verify(subscriptionBoxRepository, times(1)).findByPriceLessThan(150); - } - - @Test - void testFindByPriceGreaterThan() throws ExecutionException, InterruptedException { - List subscriptionBoxes = Arrays.asList(subscriptionBox); - when(subscriptionBoxRepository.findByPriceGreaterThan(50)).thenReturn(subscriptionBoxes); - - CompletableFuture> future = subscriptionBoxService.findByPriceGreaterThan(50); - List result = future.get(); - - assertEquals(1, result.size()); - assertEquals(subscriptionBox, result.get(0)); - verify(subscriptionBoxRepository, times(1)).findByPriceGreaterThan(50); - } - - @Test - void testFindByPriceEquals() throws ExecutionException, InterruptedException { - List subscriptionBoxes = Arrays.asList(subscriptionBox); - when(subscriptionBoxRepository.findByPriceEquals(100)).thenReturn(subscriptionBoxes); - - CompletableFuture> future = subscriptionBoxService.findByPriceEquals(100); - List result = future.get(); - - assertEquals(1, result.size()); - assertEquals(subscriptionBox, result.get(0)); - verify(subscriptionBoxRepository, times(1)).findByPriceEquals(100); - } - - @Test - void testFindByName() throws ExecutionException, InterruptedException { - List subscriptionBoxes = Arrays.asList(subscriptionBox); - when(subscriptionBoxRepository.findByName("Basic")).thenReturn(Optional.of(subscriptionBoxes)); - - CompletableFuture>> future = subscriptionBoxService.findByName("Basic"); - Optional> result = future.get(); - - assertTrue(result.isPresent()); - assertEquals(1, result.get().size()); - assertEquals(subscriptionBox, result.get().get(0)); - verify(subscriptionBoxRepository, times(1)).findByName("Basic"); - } @Test void testFindDistinctNames() throws ExecutionException, InterruptedException { From 46b544706b8daf085325091a3d082f8c8c95c193 Mon Sep 17 00:00:00 2001 From: Faishal Nelwan <108632813+pesolosep@users.noreply.github.com> Date: Thu, 23 May 2024 20:52:52 +0700 Subject: [PATCH 2/3] [REFACTOR] [GREEN] FINISH ASYNC TESTS AND IMPLEMENTATION SUBSCRIPTION BOX MANAGEMENT --- .github/workflows/ci.yml | 2 +- src/main/resources/application-dev.properties | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a833849..f9b4452 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ name: Java CI/CD Pipeline on: push: branches: - - staging + - master jobs: build: name: Build diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 4176bef..efc9449 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,12 +1,8 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/postgres -#spring.datasource.password= ${LOCAL_PASSWORD} +spring.datasource.password= ${LOCAL_PASSWORD:postgres} ## add your local postgres password here spring.datasource.username= postgres spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.format_sql=true - - - -spring.datasource.password= nelwanfamily2004 \ No newline at end of file From 39d0021adc8abb826efd6f06afaa54c87cb1ba12 Mon Sep 17 00:00:00 2001 From: Faishal Nelwan <108632813+pesolosep@users.noreply.github.com> Date: Thu, 23 May 2024 21:04:19 +0700 Subject: [PATCH 3/3] [REFACTOR] [GREEN] FINISH ASYNC TESTS AND IMPLEMENTATION SUBSCRIPTION BOX MANAGEMENT --- src/main/resources/application-dev.properties | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 4176bef..d637650 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,12 +1,13 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/postgres -#spring.datasource.password= ${LOCAL_PASSWORD} +spring.datasource.password= ${LOCAL_PASSWORD} ##add local password here spring.datasource.username= postgres spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.format_sql=true +<<<<<<< Updated upstream +======= +#bismillah +>>>>>>> Stashed changes - - -spring.datasource.password= nelwanfamily2004 \ No newline at end of file