diff --git a/media/src/main/java/com/yas/media/repository/FileSystemRepository.java b/media/src/main/java/com/yas/media/repository/FileSystemRepository.java index ee6a6b6aca..5eaca872d7 100644 --- a/media/src/main/java/com/yas/media/repository/FileSystemRepository.java +++ b/media/src/main/java/com/yas/media/repository/FileSystemRepository.java @@ -47,7 +47,7 @@ public InputStream getFile(String filePath) { } } - private Path buildFilePath(String filename) throws IOException { + private Path buildFilePath(String filename) { // Validate the filename if (filename.contains("..") || filename.contains("/") || filename.contains("\\")) { throw new IllegalArgumentException("Invalid filename"); diff --git a/media/src/test/java/com/yas/media/FileSystemRepositoryTest.java b/media/src/test/java/com/yas/media/FileSystemRepositoryTest.java index 30e25f616e..0c8fa3073d 100644 --- a/media/src/test/java/com/yas/media/FileSystemRepositoryTest.java +++ b/media/src/test/java/com/yas/media/FileSystemRepositoryTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.when; import com.yas.media.config.FilesystemConfig; import com.yas.media.repository.FileSystemRepository; @@ -12,7 +12,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; - import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -68,6 +67,18 @@ void testPersistFile_whenDirectoryNotExist_thenThrowsException() { assertThrows(IllegalStateException.class, () -> fileSystemRepository.persistFile(filename, content)); } + @Test + void testPersistFile_filePathNotContainsDirectory() { + + String filename = "test-file.png"; + byte[] content = "test-content".getBytes(); + + File directory = new File(TEST_URL); + directory.mkdirs(); + when(filesystemConfig.getDirectory()).thenReturn(TEST_URL); + assertThrows(IllegalArgumentException.class, () -> fileSystemRepository.persistFile(filename, content)); + } + @Test void testGetFile_whenDirectIsExist_thenReturnFile() throws IOException { String filename = "test-file.png"; diff --git a/order/src/it/java/com/yas/order/config/IntegrationTestConfiguration.java b/order/src/it/java/com/yas/order/config/IntegrationTestConfiguration.java new file mode 100644 index 0000000000..cc53b61b2c --- /dev/null +++ b/order/src/it/java/com/yas/order/config/IntegrationTestConfiguration.java @@ -0,0 +1,30 @@ +package com.yas.order.config; + +import dasniko.testcontainers.keycloak.KeycloakContainer; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.testcontainers.containers.PostgreSQLContainer; + +@TestConfiguration +public class IntegrationTestConfiguration { + + @Bean(destroyMethod = "stop") + public PostgreSQLContainer postgresContainer() { + return new PostgreSQLContainer<>("postgres:16") + .withReuse(true); + } + + @Bean(destroyMethod = "stop") + public KeycloakContainer keycloakContainer(DynamicPropertyRegistry registry) { + KeycloakContainer keycloak = new KeycloakContainer() + .withRealmImportFiles("/test-realm.json") + .withReuse(true); + + registry.add("spring.security.oauth2.resourceserver.jwt.issuer-uri", + () -> keycloak.getAuthServerUrl() + "/realms/quarkus"); + registry.add("spring.security.oauth2.resourceserver.jwt.jwk-set-uri", + () -> keycloak.getAuthServerUrl() + "/realms/quarkus/protocol/openid-connect/certs"); + return keycloak; + } +} \ No newline at end of file diff --git a/order/src/it/java/com/yas/order/service/OrderServiceIT.java b/order/src/it/java/com/yas/order/service/OrderServiceIT.java new file mode 100644 index 0000000000..597cb6793a --- /dev/null +++ b/order/src/it/java/com/yas/order/service/OrderServiceIT.java @@ -0,0 +1,284 @@ +package com.yas.order.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.yas.order.OrderApplication; +import com.yas.order.config.IntegrationTestConfiguration; +import com.yas.order.exception.NotFoundException; +import com.yas.order.model.Order; +import com.yas.order.model.enumeration.OrderStatus; +import com.yas.order.model.enumeration.PaymentStatus; +import com.yas.order.repository.OrderItemRepository; +import com.yas.order.repository.OrderRepository; +import com.yas.order.viewmodel.order.OrderItemPostVm; +import com.yas.order.viewmodel.order.OrderListVm; +import com.yas.order.viewmodel.order.OrderPostVm; +import com.yas.order.viewmodel.order.OrderVm; +import com.yas.order.viewmodel.order.PaymentOrderStatusVm; +import com.yas.order.viewmodel.orderaddress.OrderAddressPostVm; +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.AfterEach; +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.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +@SpringBootTest(classes = OrderApplication.class) +@Import(IntegrationTestConfiguration.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class OrderServiceIT { + + @MockBean + private ProductService productService; + + @MockBean + private CartService cartService; + + @Autowired + private OrderItemRepository orderItemRepository; + + @Autowired + private OrderRepository orderRepository; + + @Autowired + private OrderService orderService; + + private OrderItemPostVm orderItemPostVm; + + private OrderAddressPostVm orderAddressPostVm; + + private OrderPostVm orderPostVm; + + @BeforeEach + void setUp() { + orderItemPostVm = OrderItemPostVm.builder() + .productId(1L).productName("abc") + .quantity(1).productPrice(BigDecimal.TEN) + .discountAmount(BigDecimal.ONE).taxAmount(BigDecimal.ONE).taxPercent(BigDecimal.ONE) + .build(); + + orderAddressPostVm = OrderAddressPostVm.builder() + .contactName("contactName").phone("phone").addressLine1("addressLine1").addressLine2("addressLine2") + .city("city").zipCode("zipCode").districtId(1L).districtName("districtName") + .stateOrProvinceId(1L).stateOrProvinceName("stateOrProvinceName") + .countryId(1L).countryName("countryName") + .build(); + + orderPostVm = OrderPostVm.builder() + .checkoutId("1") + .email("abc@gmail.com") + .orderItemPostVms(Arrays.asList(orderItemPostVm)) + .billingAddressPostVm(orderAddressPostVm) + .shippingAddressPostVm(orderAddressPostVm) + .build(); + } + + @AfterEach + void tearDown() { + orderItemRepository.deleteAll(); + orderRepository.deleteAll(); + } + + @Test + void testCreateOrder_successful() { + + OrderVm orderVm = orderService.createOrder(orderPostVm); + + Optional orderOptional = orderRepository.findById(orderVm.id()); + assertTrue(orderOptional.isPresent()); + Order orderDb = orderOptional.get(); + assertEquals("abc@gmail.com", orderDb.getEmail()); + assertEquals(1, orderDb.getOrderItems().size()); + assertEquals("abc", orderDb.getOrderItems().stream().findFirst().get().getProductName()); + } + + @Test + void testGetOrderWithItemsById_whenNormalCase_returnOrderVm() { + orderService.createOrder(orderPostVm); + List orders = orderRepository.findAll(); + OrderVm order = orderService.getOrderWithItemsById(orders.getFirst().getId()); + assertNotNull(order); + assertEquals("abc@gmail.com", order.email()); + } + + @Test + void testGetOrderWithItemsById_whenNotFound_throwNotFoundException() { + Exception exception = assertThrows(NotFoundException.class, + () -> orderService.getOrderWithItemsById(23L)); + assertEquals("Order 23 is not found", exception.getMessage()); + } + + @Test + void testGetAllOrder_whenNormalCase_returnOrderListVm() { + + orderService.createOrder(orderPostVm); + + ZonedDateTime createdFrom = ZonedDateTime.now().minusDays(7); + ZonedDateTime createdTo = ZonedDateTime.now().plusDays(1); + String warehouse = ""; + String productName = "abc"; + List orderStatus = List.of(OrderStatus.ACCEPTED); + String billingCountry = ""; + String billingPhoneNumber = ""; + String email = "abc@gmail.com"; + int pageNo = 0; + int pageSize = 10; + + OrderListVm orderListVm = orderService.getAllOrder( + createdFrom, + createdTo, + warehouse, + productName, + orderStatus, + billingCountry, + billingPhoneNumber, + email, + pageNo, + pageSize + ); + assertNotNull(orderListVm.orderList()); + + } + + @Test + void testGetAllOrder_whenOrderPageIsEmpty_returnOrderListVm() { + + ZonedDateTime createdFrom = ZonedDateTime.now().minusDays(7); + ZonedDateTime createdTo = ZonedDateTime.now().plusDays(1); + String warehouse = "e3"; + String productName = "abc2"; + List orderStatus = List.of(OrderStatus.ACCEPTED); + String billingCountry = "e3"; + String billingPhoneNumber = "3e"; + String email = "ab2c@gmail.com"; + int pageNo = 0; + int pageSize = 10; + + OrderListVm orderListVm = orderService.getAllOrder( + createdFrom, + createdTo, + warehouse, + productName, + orderStatus, + billingCountry, + billingPhoneNumber, + email, + pageNo, + pageSize + ); + + assertNull(orderListVm.orderList()); + } + + @Test + void testFindOrderByCheckoutId_whenNormalCase_returnOrder() { + orderService.createOrder(orderPostVm); + Order order = orderService.findOrderByCheckoutId("1"); + assertNotNull(order); + assertEquals("abc@gmail.com", order.getEmail()); + } + + @Test + void testFindOrderByCheckoutId_whenNotFound_throwNotFoundException() { + Exception exception = assertThrows(NotFoundException.class, + () -> orderService.findOrderByCheckoutId("23")); + assertEquals("Order of checkoutId 23 is not found", exception.getMessage()); + } + + @Test + void testUpdateOrderPaymentStatus_whenPaymentStatusNotCompleted_returnPaymentOrderStatusVm() { + + orderService.createOrder(orderPostVm); + List orders = orderRepository.findAll(); + Order order = orders.getFirst(); + PaymentOrderStatusVm paymentOrderStatusVm = new PaymentOrderStatusVm( + order.getId(), OrderStatus.ACCEPTED.getName(), 1L, PaymentStatus.PENDING.name() + ); + + PaymentOrderStatusVm actual = orderService.updateOrderPaymentStatus(paymentOrderStatusVm); + assertEquals(OrderStatus.ACCEPTED.getName(), actual.orderStatus()); + } + + @Test + void testUpdateOrderPaymentStatus_whenNormalCase_returnPaymentOrderStatusVm() { + + orderService.createOrder(orderPostVm); + List orders = orderRepository.findAll(); + Order order = orders.getFirst(); + PaymentOrderStatusVm paymentOrderStatusVm = new PaymentOrderStatusVm( + order.getId(), OrderStatus.ACCEPTED.getName(), 1L, PaymentStatus.COMPLETED.name() + ); + + PaymentOrderStatusVm actual = orderService.updateOrderPaymentStatus(paymentOrderStatusVm); + assertEquals(OrderStatus.PAID.getName(), actual.orderStatus()); + } + + @Test + void testUpdateOrderPaymentStatus_whenNotFound_throwNotFoundException() { + + PaymentOrderStatusVm paymentOrderStatusVm = new PaymentOrderStatusVm( + 1L, OrderStatus.ACCEPTED.getName(), 1L, PaymentStatus.COMPLETED.name() + ); + + Exception exception = assertThrows(NotFoundException.class, + () -> orderService.updateOrderPaymentStatus(paymentOrderStatusVm)); + assertEquals("Order 1 is not found", exception.getMessage()); + } + + @Test + void testRejectOrder_whenNormalCase_saveOrder() { + + orderService.createOrder(orderPostVm); + List orders = orderRepository.findAll(); + Order order = orders.getFirst(); + orderService.rejectOrder(order.getId(), "test reason"); + + Optional actual = orderRepository.findById(order.getId()); + assertNotNull(actual); + if (actual.isPresent()) { + assertEquals(OrderStatus.REJECT, actual.get().getOrderStatus()); + assertEquals("test reason", actual.get().getRejectReason()); + } + + } + + @Test + void testRejectOrder_whenNotFound_throwNotFoundException() { + Exception exception = assertThrows(NotFoundException.class, + () -> orderService.rejectOrder(1L, "test reason 2")); + assertEquals("Order 1 is not found", exception.getMessage()); + } + + + @Test + void testAcceptOrder_whenNormalCase_saveOrder() { + orderService.createOrder(orderPostVm); + List orders = orderRepository.findAll(); + Order order = orders.getFirst(); + orderService.acceptOrder(order.getId()); + + Optional actual = orderRepository.findById(order.getId()); + assertNotNull(actual); + actual.ifPresent(value -> assertEquals(OrderStatus.ACCEPTED, value.getOrderStatus())); + } + + @Test + void testAcceptOrder_whenNotFound_throwNotFoundException() { + Exception exception = assertThrows(NotFoundException.class, + () -> orderService.acceptOrder(2L)); + assertEquals("Order 2 is not found", exception.getMessage()); + } + + +} diff --git a/order/src/it/resources/mockito-extensions/org.mockito.plugins.MockMaker b/order/src/it/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..be144a36cb --- /dev/null +++ b/order/src/it/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1,2 @@ +mock-maker-inline + diff --git a/order/src/it/resources/test-realm.json b/order/src/it/resources/test-realm.json new file mode 100644 index 0000000000..ecf799f97d --- /dev/null +++ b/order/src/it/resources/test-realm.json @@ -0,0 +1,1857 @@ +{ + "id" : "quarkus", + "realm" : "quarkus", + "notBefore" : 0, + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 300, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "enabled" : true, + "sslRequired" : "external", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ + { + "id": "f2da71cd-654f-4beb-8ec8-fa78d6fc1219", + "name": "default-roles-yas", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ] + }, + "clientRole": false, + "containerId": "Yas", + "attributes": {} + }, + { + "id": "eadee165-c7b4-4508-bf60-937580c5d987", + "name": "ADMIN", + "composite": false, + "clientRole": false, + "containerId": "Yas", + "attributes": {} + }, + { + "id" : "5ae801de-cd65-42c1-ac5e-3b051abadcff", + "name" : "admin", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + }, { + "id" : "2bca19e3-c333-41fb-8549-526536f039fb", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + }, { + "id" : "c924843b-38ab-4c85-871c-86f6e0b47500", + "name" : "user", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + }, { + "id" : "589c3954-acfd-4689-815d-d3e7ce172045", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "1c1db47d-3e9f-4bcb-aa37-b5b4b0d67942", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "f3deb521-8e02-4496-a242-e015c32e42ad", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "e9f35eb2-f3e6-41ac-aac9-0f540fbb1f2d", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "83d46ffc-8744-4fd6-a407-75098529adb7", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "23f29143-b35a-4f3d-88bf-b1ac603ca86f", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "ece87aaa-bbb1-48dc-b663-48a36dbb732a", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "9b9d045d-2884-41ae-9a2a-484907ff664d", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "89f6649a-1d40-4fab-a005-b892d6589764", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "8414a9d2-4ae1-45bb-8746-d0d857067f97", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "e02cdfef-d0ec-4e34-9457-76294b42adc5", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "85cd6885-cb73-4ac8-93ec-8fc4d7c75999", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "c8214f22-687a-45cb-a575-dea31b92ebe8", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "4e01ff83-6d49-48e6-bbc1-37dff1bf876b", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "0dc9eda3-37dd-46d5-8130-39046f3bcaf9", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "a39504b0-e679-4e59-ab14-3c7727a4f5c3", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "e1a6e15d-4b77-4a77-9348-bfc3190e2a2d", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "3f29e90a-1f05-4f8e-82b6-32a39127d73b", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "view-identity-providers", "manage-identity-providers", "manage-authorization", "view-events", "manage-realm", "create-client", "manage-clients", "view-authorization", "query-realms", "query-clients", "view-clients", "manage-users", "view-realm", "impersonation", "query-groups", "view-users", "query-users", "manage-events" ] + } + }, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "7b3322f1-7bc8-456a-ab1f-9f06a4af9311", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "0bb5515b-adc3-495e-8e38-d34bac2162a6", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "quarkus-service" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "7a996641-0139-4e46-9cf8-96273e57d0ba", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "d4c8f765-b8b3-44fa-a99c-4001172f98f3", + "attributes" : { } + } ], + "account" : [ { + "id" : "4f26a889-000a-41ee-b3cc-c6db5a344833", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "04c2755b-e926-467b-983e-3eb3bb23e5a5", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "ee3d20f8-544f-49d9-b98c-0e46589c67f1", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "3b991fa9-2469-402a-a249-fb237cf6f364", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "79fdb572-7eb9-4236-adc1-61d95d9e10d2", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "66ddea7c-27a7-4ab9-bc0b-bf404ab84199", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "dad36647-a910-4b97-b8eb-4248dfc37252", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + } ] + } + }, + "groups" : [ ], + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ], + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "users" : [ { + "id" : "7d40c686-612a-4b49-93fd-e28244f40136", + "createdTimestamp" : 1617800939748, + "username" : "admin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "Admin", + "lastName" : "Admin", + "email" : "admin@localhost", + "credentials" : [ { + "id" : "b68a1141-f42e-4cba-8c7a-97a47fb81857", + "type" : "password", + "createdDate" : 1617800952774, + "secretData" : "{\"value\":\"5VL5vW+2wIu0SCW7Fy5EzktX5X6LkiDNjCp2MLrdudF9EiR3rs12dhGTHs5wyXlK9944I4e3iBsK01EVuzEXPw==\",\"salt\":\"6tTNIudRbWQhlZBB8vkjRg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles": ["default-roles-yas", "ADMIN"], + "clientRoles" : { + "account" : [ "view-profile", "manage-account" ] + }, + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "af9b247a-ff16-424b-af38-e7473c16a406", + "createdTimestamp" : 1617800970630, + "username" : "john", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "John", + "lastName" : "Doe", + "email" : "john@localhost", + "credentials" : [ { + "id" : "e86c9af1-5e25-4918-bc70-457a3aade97b", + "type" : "password", + "createdDate" : 1617800978521, + "secretData" : "{\"value\":\"oMEimHrxfSIjQsi3bwdynWL3xUusgXK3YiaWV1bRtN+2yRFuPWDQ3UbeppxSH9DDJuI9euZuwFMsb3PUOgs78Q==\",\"salt\":\"8jLTvRKcWnSo8/Z5+vCG3A==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "user" ], + "clientRoles" : { + "account" : [ "view-profile", "manage-account" ] + }, + "notBefore" : 0, + "groups" : [ ] + } ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account" ] + } ] + }, + "clients" : [ { + "id" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/quarkus/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "46c49daf-fa62-4744-883d-d32e810cfb9c", + "defaultRoles" : [ "view-profile", "manage-account" ], + "redirectUris" : [ "/realms/quarkus/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "0e2c27dd-f217-4926-a575-4c59171f9f39", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/quarkus/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "134ac396-96f5-432a-8241-faf3de2711f6", + "redirectUris" : [ "/realms/quarkus/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "ed59083f-a6e7-41f5-8caf-c49dfa04b969", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "6f9a7a50-f05f-4833-8dba-2492a2a70b40", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "8caf9d87-7e94-4597-931a-4cb5357e72b2", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "d4c8f765-b8b3-44fa-a99c-4001172f98f3", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "590e533b-5a2d-4dd1-9419-d301f326cf0a", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "56443d41-f71f-490f-872c-5daa01b31a28", + "clientId" : "quarkus-service", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "secret", + "redirectUris" : [ "/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : true, + "authorizationServicesEnabled": true, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.assertion.signature" : "false", + "saml.multivalued.roles" : "false", + "saml.force.post.binding" : "false", + "saml.encrypt" : "false", + "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "exclude.session.state.from.auth.response" : "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required" : "true", + "client_credentials.use_refresh_token" : "false", + "saml_force_name_id_format" : "false", + "saml.client.signature" : "false", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], + "authorizationSettings": { + "allowRemoteResourceManagement": true, + "policyEnforcementMode": "ENFORCING", + "resources": [ + { + "name": "Admin Resource", + "ownerManagedAccess": false, + "attributes": {}, + "_id": "d2b855d4-61f6-4159-9b89-b0257ad380c9", + "uris": [ + "/admin/*" + ], + "icon_uri": "" + }, + { + "name": "User Resource", + "ownerManagedAccess": false, + "attributes": {}, + "_id": "6f589c2e-160c-487b-8e8c-8141dc441b2a", + "uris": [ + "/users/*" + ], + "icon_uri": "" + } + ], + "policies": [ + { + "id": "2aaaff19-710d-479d-80b8-ef57e4e258d8", + "name": "Any User Policy", + "description": "Any user granted with the user role can access something", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"user\",\"required\":false}]" + } + }, + { + "id": "43b4ae35-5fc4-45d7-b0a2-501e772ecb84", + "name": "Only Admins", + "description": "Only administrators can access", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"admin\",\"required\":false}]" + } + }, + { + "id": "06fc24d8-1f84-46f4-ae7b-e13a505195f1", + "name": "User Resource Permission", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "defaultResourceType": "", + "resources": "[\"User Resource\"]", + "applyPolicies": "[\"Any User Policy\"]" + } + }, + { + "id": "d75310e2-8b14-4c88-9148-2fa82220e30b", + "name": "Admin Resource Permission", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Admin Resource\"]", + "applyPolicies": "[\"Only Admins\"]" + } + } + ], + "scopes": [], + "decisionStrategy": "UNANIMOUS" + } + }, { + "id" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "70fd3aa0-f353-4860-9a67-5eb86684e0a8", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "b720bc75-35bf-4dcd-a5a9-90d1267a3b04", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/quarkus/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "55fbb9e1-4410-48b7-b1ad-7b043144b859", + "redirectUris" : [ "/admin/quarkus/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "44e02e60-ae62-4b32-b20b-226565749528", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "0110b627-1823-4aa2-9c12-e25eb8bc1d24", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "14a58948-73a4-4679-ae93-93e7cf91f337", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "203f72b9-e269-4433-a1d6-5067a82e6029", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "e8d6fa1d-5d10-4388-a815-b8cc269cf521", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${profileScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "e0d1b63e-956f-43aa-8bf0-5331d2b6160c", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "dfa55ca4-9c69-4238-bebf-9bcc9144508e", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "bae556b2-5a2e-4eea-b5cb-717e0c4cbf5f", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "9a4b7133-a0f3-4043-884e-b9bf571c81d7", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "6164139c-c1f4-44bb-9c22-800e2d21ca09", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "527d79d0-1966-4b90-92f0-0b54c623d596", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "String" + } + }, { + "id" : "39655902-2b3a-4205-a8db-03ad38bb4df6", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "3e9b71e1-0829-4a57-80ff-09f2718abf13", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "d6f5b49a-df41-4fee-93ec-246e5202fdff", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "5a648f3a-07d2-4c8d-afe8-c1accb9b1187", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "b7e2d1ac-2517-4df1-b9a9-afb925339731", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "0c2ab3b5-f6c6-45d8-8894-3cf71dc6fb38", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "9e7b6084-7a84-4699-9b51-d619094f4ff9", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "61ab8691-6995-4d4f-8917-67093c8aedfb", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "183a7265-5d2a-41bd-baf0-dd376b366063", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "887b7325-71e4-4eac-a197-6948862cb928", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "7f540ab7-f7b6-41d7-b56c-5b63ec354abe", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "bf8af7d9-fff7-427e-880e-62ea16ab94e9", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "cd85be29-34ed-47e2-b0ce-2270f8061f09", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "abed9a36-8900-4eec-9d58-9528f6f284ac", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${phoneScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "ef60ce57-9cfa-449c-9624-f74a16944327", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "b3636e01-5cb1-4ce2-b08a-913f15bbc738", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "2036bd5e-f33d-442d-8ed0-6bf9a50ad45d", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${rolesScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "73ac1825-7ac3-40ad-8f38-b2620808b02f", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "0d0ca6ec-e6cc-425f-ba92-2ed4b7778faf", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + }, { + "id" : "aa5d7eab-30e5-49eb-a4fe-4ad425fffd64", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + }, { + "id" : "4c7b020d-ab2d-4cee-a9c1-26b5a28453df", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "9762fd5d-17bf-4666-b538-0adee5f584c3", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "92cb2a60-3a1f-4bf1-94b9-078e80cff964", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "1354aade-9a9f-41db-a462-f2071532fd6f", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "multivalued" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + }, { + "id" : "0e78dfa6-86dd-4960-a23b-44c3329df528", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins" ], + "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "a033e338-3cfe-4440-85dd-ec4a332742fd", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "66eb3397-e784-4b4d-8242-5385453197b7", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper" ] + } + }, { + "id" : "3e836a32-ff93-46e6-8e1f-7e320507388f", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "bad9c53c-6b7b-431f-a4f4-62970f9af1e2", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "174410e0-cd98-4a90-bfc3-68a8980b87e7", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "2b9ca142-85a0-448d-bde9-800f7823cac1", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "4271132b-929b-4b76-a94e-aeafa71715ec", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "6ab250a9-d27b-4c5c-8cdf-0b8adee370d4", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "e7f99358-99f3-4fb6-a65d-5771a0c07f38", + "name" : "hmac-generated", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "a7c0b05e-7852-492d-a712-30ce7c6e48a6" ], + "secret" : [ "gh6Ab3iAF2CiWam3ly0OZcwfMPRNn6s0lgqmn177iHBSebirfHRkahPjJGmGVHS9fmqRidaOV8v1YoxF0lhv5Q" ], + "priority" : [ "100" ], + "algorithm" : [ "HS256" ] + } + }, { + "id" : "30fe7115-b6e4-4ed8-b350-73a160895f4c", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEAnTsWCUKow1fwyn/p38MM7SfuS1KzDGGWPLcrt4r6Hy2vPG8G6psABbkA2+if5y+614vjLKaG2g33bU4OkoVOcGtISMN+Fc2J+i/Fd250PaLCe89uRzrHc2q+6bgMuvOnNtcOJqR+Y+Zrs34kG0izWe+dHTNrgav4WKbpKzAR3ZlCNIkVU81m2LG+u6MyQJpN3RiOaeBC/vtxCGHPO4BTHA4cCeXVd8P9Gczh5WqSH+Es5dQRxfLiWDLbV+BeAeDvJIhJq8yuLkjBBnq1w5TASVf8U+LsVVWCwUy/lDXDX7G2EVU+BRq9hfRPRkiXcN+CigZVr6b8JXdUH4Kh/PF2QwIDAQABAoIBAG1YLw4HnqgjW2DorjQgSLgRYgZeIAjHQR0+YZfGfgX61nhX2l6DpvNT4sYMtE+qAO1v6nAd64Bv4BfTBg1dydwir+VylxgAlik42cIiPZKzwz8pVc8RkK2ymcyeY7QMSMi5rKyxDvjYwSPV4LRczeYI3qH1JZnLh+3XPib7yiDqIQhMEPxxdOGzidwSwijTzVfOt5ltsk5T4ZCsGpWvoGnvNQYRlt4AdewGP0Mg0hacS21y5M6B1he+z9Tnb2/uIloGvEBHNCPsvn6qXmszoZhKH4FueP6cfgO4342jR8ksEhwlpgmAQ87B5zabMyRbstnazr1Am1dgCAQRto+xFXECgYEA3e8rqymsdVwnbjFsSv6K67SvnJdqFFHAcdzqeCoOsy0JBlb3ck9zvW/8R0dMx0YQ83dxlvKxCESOhroSHQ4P38N4t4CeOOSPhBnYFnfc3n75ckro1fp3WWL4Dq/oN63wiaNQCISz5HYdqXs9GXMVn5GRS8kr70qa3PrXY8RGa/sCgYEAtV1qcEoqMUVQGSYF3eWlXqTVn4RvonIg87Jw/dnaPnSUcy8+80+ipJiCInzRsZ+ApPNie+VStdg7mz0pDGkA9vqDX1SQYsp5XcCtq49Pt+Oc8woPowjY+rU8Us5v+BYM2RjAhO85+obsXkPchQsC+au6IODrA3awGHb5cuNyBFkCgYEAnbpqTbZLdAkvmNgVP+NR9hyvJlpSMOi9He9E0GwLkHn0TQYnzJz9A+h/4mShA4sfZvk/yGjpOpgGt2eskeu5im1Q8RG+4W5HNTps4eMEHTkerYThn5nnkqaM51tLba74IcnoinVNqJPtltMYZGrvNj3thnAOAn4CPAUmaShIaFsCgYAkWLpSEqruAOQShio61CEWHJarR1FQDutHq4U1eolgZuCxTNCi1lzT+7Ro0Pb9T+fqJtSf2899nf4kGFe3ovuMg5v8aOgexFEaVtj3PttNERKNKoEDvWwuok+akMCjyVd90pYSjhbifFO2eIcjKpfIDYBZwnmW0hxsaruHKMna0QKBgEYF8xk/XqDViV2a7C8byQNBXwFWzct+rcdj9yOMqdWl8XTBU7Tf2YojRKGjkpMHnrNbDCQPUYcKoIYZBWdkiufe5WTDU/3yLZjbMl+9jC9MQ3sXSZqWEqsdKDFZVFFXWNMxbmSPZMLWm3kWM0yxGg3e2il/NHpiNjssEz/toasC" ], + "certificate" : [ "MIICnTCCAYUCBgF4rE75SjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdxdWFya3VzMB4XDTIxMDQwNzEyMjc0MFoXDTMxMDQwNzEyMjkyMFowEjEQMA4GA1UEAwwHcXVhcmt1czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ07FglCqMNX8Mp/6d/DDO0n7ktSswxhljy3K7eK+h8trzxvBuqbAAW5ANvon+cvuteL4yymhtoN921ODpKFTnBrSEjDfhXNifovxXdudD2iwnvPbkc6x3Nqvum4DLrzpzbXDiakfmPma7N+JBtIs1nvnR0za4Gr+Fim6SswEd2ZQjSJFVPNZtixvrujMkCaTd0YjmngQv77cQhhzzuAUxwOHAnl1XfD/RnM4eVqkh/hLOXUEcXy4lgy21fgXgHg7ySISavMri5IwQZ6tcOUwElX/FPi7FVVgsFMv5Q1w1+xthFVPgUavYX0T0ZIl3DfgooGVa+m/CV3VB+CofzxdkMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACWVoMh1jB64LEiOzHrwDWeWDHRZMrb1TBcfC6ALjFDBako0AbSHxBqN6FJgN6C3BhzCBcI4LR6I8bpqGuZ9y9zE8hRj8oAtEAXnPdMSWsWEBBFdbSBDeBE9Q8jXJ5LCk+Iz/5HcPJTgUpkJdKmzIWqp1hI4zOb1+GZrERg04Ue+xP6DTCOZkcofA3twzqM0Eifig8UoSUlejUKXCISbcO39slcFNGbPDPsUNjWUgVG79TZExtF02KmbzEifh+aQi0jb3/d5gSPEOSW+n8CC/zW0woDZQ4ZhspDUeQyIafy0JPlgZljsWBbWpJ0ZJIiWVTWxO7T1ogiyFtLoX2sinJA==" ], + "priority" : [ "100" ] + } + }, { + "id" : "1d927d6c-779e-4fea-a2a4-a3dd194c1a8f", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "12395eb8-d68a-4272-b88e-3e2a2096e2e6" ], + "secret" : [ "uqAMrTEXiIXom7DjxnnWEw" ], + "priority" : [ "100" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "0b0bb974-6484-4dbc-bc0c-7a3ce27a1a2f", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "ALTERNATIVE", + "priority" : 20, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "b7f60e5e-94c8-4ede-ab61-ced8b2fea44a", + "alias" : "Authentication Options", + "description" : "Authentication options.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "basic-auth", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "basic-auth-otp", + "requirement" : "DISABLED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-spnego", + "requirement" : "DISABLED", + "priority" : 30, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "423fe6a4-3445-4731-8ac3-23e348b08743", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-otp-form", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "c60ff278-6c63-4d7e-ad1c-7c4e825199a6", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "d5bde955-3a6e-47d2-9289-fdd28e1d1c45", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-otp-form", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "2fc18574-8dc9-4a4f-9dbf-f7b221a978bc", + "alias" : "Handle Existing Account", + "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "REQUIRED", + "priority" : 20, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "306c3c73-3d32-44ce-8781-e2cde85d7823", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "reset-otp", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "ee1b35cd-1378-4d4d-b47b-f769afafb8a8", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "ALTERNATIVE", + "priority" : 20, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "3c4a0468-ac42-4f2c-9fc5-34520bac4645", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 20, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "8115c879-0792-4557-896c-91a529d68cf6", + "alias" : "browser", + "description" : "browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-spnego", + "requirement" : "DISABLED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "identity-provider-redirector", + "requirement" : "ALTERNATIVE", + "priority" : 25, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "ALTERNATIVE", + "priority" : 30, + "flowAlias" : "forms", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "a407f9a2-8671-4fe0-b5c6-03e29e115337", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "client-jwt", + "requirement" : "ALTERNATIVE", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "client-secret-jwt", + "requirement" : "ALTERNATIVE", + "priority" : 30, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "client-x509", + "requirement" : "ALTERNATIVE", + "priority" : 40, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "0f232cb6-6904-4c1f-948e-e221300fa518", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "direct-grant-validate-password", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 30, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "a57ab792-c919-4f99-b662-a4e142d7c035", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "d0327c66-d41e-45d1-898c-0dae3dc3a149", + "alias" : "first broker login", + "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "REQUIRED", + "priority" : 20, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "7af247e0-a6b9-4fed-857d-d14258acd2b8", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 20, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "12c84fcd-ed90-4b34-b8be-5208945939ef", + "alias" : "http challenge", + "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "no-cookie-redirect", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "REQUIRED", + "priority" : 20, + "flowAlias" : "Authentication Options", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "c2c34d02-e57f-4341-8c05-272b5fef9f60", + "alias" : "registration", + "description" : "registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "requirement" : "REQUIRED", + "priority" : 10, + "flowAlias" : "registration form", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "ee5eb12c-033b-481b-9a91-466f3bc02581", + "alias" : "registration form", + "description" : "registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "registration-profile-action", + "requirement" : "REQUIRED", + "priority" : 40, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "registration-password-action", + "requirement" : "REQUIRED", + "priority" : 50, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "registration-recaptcha-action", + "requirement" : "DISABLED", + "priority" : 60, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "320a7e68-e3ab-4142-a660-e2a25a434287", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "reset-credential-email", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "reset-password", + "requirement" : "REQUIRED", + "priority" : 30, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 40, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "1ad6cd70-f740-4411-bd1c-35628d7878b3", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "9e1bf425-f911-41fe-b17e-0217b929bc22", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "7fa0e793-a298-4584-a629-f206a1f33944", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "terms_and_conditions", + "name" : "Terms and Conditions", + "providerId" : "terms_and_conditions", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "attributes" : { + "clientOfflineSessionMaxLifespan" : "0", + "clientSessionIdleTimeout" : "0", + "clientSessionMaxLifespan" : "0", + "clientOfflineSessionIdleTimeout" : "0" + }, + "keycloakVersion" : "12.0.1", + "userManagedAccessAllowed" : false +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/controller/CheckoutControllerTest.java b/order/src/test/java/com/yas/order/controller/CheckoutControllerTest.java new file mode 100644 index 0000000000..dd52327d34 --- /dev/null +++ b/order/src/test/java/com/yas/order/controller/CheckoutControllerTest.java @@ -0,0 +1,171 @@ +package com.yas.order.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +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.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.yas.order.OrderApplication; +import com.yas.order.service.CheckoutService; +import com.yas.order.viewmodel.checkout.CheckoutItemPostVm; +import com.yas.order.viewmodel.checkout.CheckoutItemVm; +import com.yas.order.viewmodel.checkout.CheckoutPostVm; +import com.yas.order.viewmodel.checkout.CheckoutStatusPutVm; +import com.yas.order.viewmodel.checkout.CheckoutVm; +import java.math.BigDecimal; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.jetbrains.annotations.NotNull; +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; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +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.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@ExtendWith(SpringExtension.class) +@WebMvcTest(controllers = CheckoutController.class) +@ContextConfiguration(classes = OrderApplication.class) +@AutoConfigureMockMvc(addFilters = false) +class CheckoutControllerTest { + + @MockBean + private CheckoutService checkoutService; + + @Autowired + private MockMvc mockMvc; + + private ObjectWriter objectWriter; + + @BeforeEach + void setUp() { + objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter(); + } + + @Test + void testCreateCheckout_whenRequestIsValid_thenReturnCheckoutVm() throws Exception { + + CheckoutVm response = getCheckoutVm(); + when(checkoutService.createCheckout(any(CheckoutPostVm.class))).thenReturn(response); + + List items = getCheckoutItemPostVms(); + CheckoutPostVm request = new CheckoutPostVm( + "customer@example.com", + "Please deliver before noon.", + "SUMMER2024", + items + ); + + mockMvc.perform(post("/storefront/checkouts") + .contentType(MediaType.APPLICATION_JSON) + .content(objectWriter.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(response))); + + } + + @Test + void testUpdateCheckoutStatus_whenRequestIsValid_thenReturnLong() throws Exception { + + CheckoutStatusPutVm request = new CheckoutStatusPutVm("1", "2"); + Long response = 123L; + when(checkoutService.updateCheckoutStatus(any(CheckoutStatusPutVm.class))).thenReturn(response); + + mockMvc.perform(put("/storefront/checkouts/status") + .contentType(MediaType.APPLICATION_JSON) + .content(objectWriter.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(response))); + } + + @Test + void testGetOrderWithItemsById_whenRequestIsValid_thenReturnCheckoutVm() throws Exception { + + String id = "123"; + CheckoutVm response = getCheckoutVm(); + when(checkoutService.getCheckoutPendingStateWithItemsById(id)).thenReturn(response); + + mockMvc.perform(get("/storefront/checkouts/{id}", id) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(response))); + } + + + private static @NotNull List getCheckoutItemPostVms() { + CheckoutItemPostVm item1 = new CheckoutItemPostVm( + 101L, + "Product One", + 3, + new BigDecimal("29.99"), + "First item note", + new BigDecimal("5.00"), + new BigDecimal("2.50"), + new BigDecimal("8.5") + ); + + CheckoutItemPostVm item2 = new CheckoutItemPostVm( + 102L, + "Product Two", + 1, + new BigDecimal("49.99"), + "Second item note", + new BigDecimal("10.00"), + new BigDecimal("5.00"), + new BigDecimal("10.0") + ); + + return List.of(item1, item2); + } + + private CheckoutVm getCheckoutVm() { + CheckoutItemVm item1 = CheckoutItemVm.builder() + .id(1L) + .productId(101L) + .productName("Product 1") + .quantity(2) + .productPrice(new BigDecimal("19.99")) + .note("First item note") + .discountAmount(new BigDecimal("2.00")) + .taxAmount(new BigDecimal("1.50")) + .taxPercent(new BigDecimal("5.0")) + .checkoutId("checkout123") + .build(); + + CheckoutItemVm item2 = CheckoutItemVm.builder() + .id(2L) + .productId(102L) + .productName("Product 2") + .quantity(1) + .productPrice(new BigDecimal("9.99")) + .note("Second item note") + .discountAmount(new BigDecimal("1.00")) + .taxAmount(new BigDecimal("0.75")) + .taxPercent(new BigDecimal("5.0")) + .checkoutId("checkout123") + .build(); + + Set checkoutItemVms = new HashSet<>(); + checkoutItemVms.add(item1); + checkoutItemVms.add(item2); + + return new CheckoutVm( + "checkout123", + "user@example.com", + "Please deliver after 5 PM", + "DISCOUNT20", + checkoutItemVms + ); + } +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/controller/OrderControllerTest.java b/order/src/test/java/com/yas/order/controller/OrderControllerTest.java new file mode 100644 index 0000000000..51da0746b4 --- /dev/null +++ b/order/src/test/java/com/yas/order/controller/OrderControllerTest.java @@ -0,0 +1,376 @@ +package com.yas.order.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +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.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.yas.order.OrderApplication; +import com.yas.order.model.enumeration.DeliveryMethod; +import com.yas.order.model.enumeration.DeliveryStatus; +import com.yas.order.model.enumeration.OrderStatus; +import com.yas.order.model.enumeration.PaymentMethod; +import com.yas.order.model.enumeration.PaymentStatus; +import com.yas.order.service.OrderService; +import com.yas.order.viewmodel.order.OrderExistsByProductAndUserGetVm; +import com.yas.order.viewmodel.order.OrderGetVm; +import com.yas.order.viewmodel.order.OrderItemPostVm; +import com.yas.order.viewmodel.order.OrderItemVm; +import com.yas.order.viewmodel.order.OrderListVm; +import com.yas.order.viewmodel.order.OrderPostVm; +import com.yas.order.viewmodel.order.OrderVm; +import com.yas.order.viewmodel.order.PaymentOrderStatusVm; +import com.yas.order.viewmodel.orderaddress.OrderAddressPostVm; +import com.yas.order.viewmodel.orderaddress.OrderAddressVm; +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +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; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +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.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@ExtendWith(SpringExtension.class) +@WebMvcTest(controllers = OrderController.class) +@ContextConfiguration(classes = OrderApplication.class) +@AutoConfigureMockMvc(addFilters = false) +class OrderControllerTest { + + @MockBean + private OrderService orderService; + + @Autowired + private MockMvc mockMvc; + + private ObjectWriter objectWriter; + + @BeforeEach + void setUp() { + objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter(); + } + + @Test + void testCreateOrder_whenRequestIsValid_thenReturnOrderVm() throws Exception { + + OrderPostVm request = getOrderPostVm(); + OrderVm response = getOrderVm(); + when(orderService.createOrder(request)).thenReturn(response); + + mockMvc.perform(post("/storefront/orders") + .contentType(MediaType.APPLICATION_JSON) + .content(objectWriter.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(response))); + } + + @Test + void testUpdateOrderPaymentStatus_whenRequestIsValid_thenReturnPaymentOrderStatusVm() + throws Exception { + + PaymentOrderStatusVm request = new PaymentOrderStatusVm( + 1001L, + "Completed", + 5001L, + "Paid" + ); + + PaymentOrderStatusVm response = new PaymentOrderStatusVm( + 12345L, + "Shipped", + 67890L, + "Completed" + ); + + when(orderService.updateOrderPaymentStatus(request)).thenReturn(response); + + mockMvc.perform(put("/storefront/orders/status") + .contentType(MediaType.APPLICATION_JSON) + .content(objectWriter.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(response))); + } + + @Test + void testCheckOrder_whenRequestIsValid_thenReturnOrderExistsByProductAndUserGetVm() throws Exception { + + Long productId = 1L; + OrderExistsByProductAndUserGetVm orderExistsByProductAndUserGetVm + = new OrderExistsByProductAndUserGetVm(false); + when(orderService.isOrderCompletedWithUserIdAndProductId(productId)) + .thenReturn(orderExistsByProductAndUserGetVm); + + mockMvc.perform(get("/storefront/orders/completed").param("productId", productId.toString()) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content() + .json(objectWriter.writeValueAsString(orderExistsByProductAndUserGetVm))); + } + + @Test + void testGetMyOrders_whenRequestIsValid_thenReturnOrderGetVm() throws Exception { + + String productName = "test-name"; + OrderStatus orderStatus = OrderStatus.COMPLETED; + + OrderGetVm order1 = new OrderGetVm( + 1L, + OrderStatus.COMPLETED, + new BigDecimal("100.00"), + DeliveryStatus.CANCELLED, + DeliveryMethod.GRAB_EXPRESS, + List.of(), + null + ); + OrderGetVm order2 = new OrderGetVm( + 2L, + OrderStatus.COMPLETED, + new BigDecimal("150.00"), + DeliveryStatus.DELIVERED, + DeliveryMethod.GRAB_EXPRESS, + List.of(), + null + ); + + when(orderService.getMyOrders(productName, orderStatus)) + .thenReturn(List.of(order1, order2)); + + mockMvc.perform(get("/storefront/orders/my-orders") + .param("productName", productName) + .param("orderStatus", orderStatus.toString()) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content() + .json(objectWriter.writeValueAsString(List.of(order1, order2)))); + } + + @Test + void testGetOrderWithItemsById_whenRequestIsValid_thenReturnOrderVm() throws Exception { + + long productId = 1L; + OrderVm orderVm = getOrderVm(); + when(orderService.getOrderWithItemsById(productId)) + .thenReturn(orderVm); + + mockMvc.perform(get("/backoffice/orders/{id}", productId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content() + .json(objectWriter.writeValueAsString(orderVm))); + } + + @Test + void testGetOrders_whenRequestIsValid_thenReturnOrderListVm() throws Exception { + + OrderListVm orderListVm = new OrderListVm( + null, + 2L, + 1 + ); + when(orderService.getAllOrder( + any(), + any(), + anyString(), + anyString(), + anyList(), + anyString(), + anyString(), + anyString(), + anyInt(), + anyInt() + )).thenReturn(orderListVm); + + mockMvc.perform(get("/backoffice/orders") + .param("createdFrom", "1970-01-01T00:00:00Z") + .param("createdTo", ZonedDateTime.now().toString()) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.content() + .json(objectWriter.writeValueAsString(orderListVm))); + } + + private OrderVm getOrderVm() { + + OrderAddressVm shippingAddress = new OrderAddressVm( + 1L, + "John Doe", + "+1234567890", + "123 Elm Street", + "Apt 3B", + "Springfield", + "62704", + 10L, + "Downtown", + 20L, + "Illinois", + 30L, + "United States" + ); + + OrderAddressVm billingAddress = new OrderAddressVm( + 1L, + "Jane Smith", + "+1987654321", + "789 Pine Street", + "Suite 202", + "Metropolis", + "12345", + 102L, + "North District", + 202L, + "California", + 302L, + "United States" + ); + + Set items = getOrderItemVms(); + + return new OrderVm( + 1001L, + "alice.johnson@example.com", + shippingAddress, + billingAddress, + "Please deliver by next week.", + 7.50f, + 15.00f, + 3, + new BigDecimal("159.97"), + new BigDecimal("7.99"), + "WINTER2024", + OrderStatus.COMPLETED, + DeliveryMethod.GRAB_EXPRESS, + DeliveryStatus.PREPARING, + PaymentStatus.COMPLETED, + items + ); + } + + private Set getOrderItemVms() { + OrderItemVm item1 = new OrderItemVm( + 1L, + 101L, + "Smartphone", + 2, + new BigDecimal("299.99"), + "Latest model with extended warranty", + new BigDecimal("20.00"), + new BigDecimal("24.00"), + new BigDecimal("8.00"), + 1001L + ); + + OrderItemVm item2 = new OrderItemVm( + 12L, + 102L, + "Smartphone 2", + 2, + new BigDecimal("299.99"), + "Latest model with extended warranty", + new BigDecimal("20.00"), + new BigDecimal("24.00"), + new BigDecimal("8.00"), + 1001L + ); + + Set items = new HashSet<>(); + items.add(item1); + items.add(item2); + return items; + } + + private OrderPostVm getOrderPostVm() { + + OrderAddressPostVm shippingAddress = new OrderAddressPostVm( + "John Doe", + "+123456789", + "123 Main St", + "Apt 4B", + "Springfield", + "62701", + 101L, + "Downtown", + 201L, + "Illinois", + 301L, + "USA" + ); + + OrderAddressPostVm billingAddress = new OrderAddressPostVm( + "Jane Smith", + "+1987654321", + "789 Elm Street", + "Suite 5A", + "Greenville", + "29601", + 102L, + "North District", + 202L, + "South Carolina", + 302L, + "United States" + ); + + List items = getOrderItemPostVms(); + + return new OrderPostVm( + "checkoutId123", + "customer@example.com", + shippingAddress, + billingAddress, + "Please handle with care.", + 5.00f, + 10.00f, + 2, + new BigDecimal("89.97"), + new BigDecimal("5.00"), + "COUPON2024", + DeliveryMethod.YAS_EXPRESS, + PaymentMethod.BANKING, + PaymentStatus.COMPLETED, + items + ); + } + + private List getOrderItemPostVms() { + OrderItemPostVm item1 = new OrderItemPostVm( + 123L, + "Wireless Mouse", + 2, + new BigDecimal("25.99"), + "Includes batteries", + new BigDecimal("5.00"), + new BigDecimal("2.00"), + new BigDecimal("8.00") + ); + + OrderItemPostVm item2 = new OrderItemPostVm( + 1234L, + "Wireless Mouse 2", + 3, + new BigDecimal("25.99"), + "Includes batteries", + new BigDecimal("5.00"), + new BigDecimal("2.00"), + new BigDecimal("8.00") + ); + + return List.of(item1, item2); + } + +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/mapper/CheckoutMapperTest.java b/order/src/test/java/com/yas/order/mapper/CheckoutMapperTest.java index 0d88afe079..8281883b97 100644 --- a/order/src/test/java/com/yas/order/mapper/CheckoutMapperTest.java +++ b/order/src/test/java/com/yas/order/mapper/CheckoutMapperTest.java @@ -15,16 +15,17 @@ @ExtendWith(SpringExtension.class) @SpringBootTest(classes = {CheckoutMapperImpl.class}) class CheckoutMapperTest { + @Autowired CheckoutMapper checkoutMapper; @Test void testCheckoutItemPostVmToModel_convertToCorrectCheckoutItem(){ - // set up + var src = Instancio.create(CheckoutItemPostVm.class); - // run + var res = checkoutMapper.toModel(src); - // assert + Assertions.assertThat(res) .hasFieldOrPropertyWithValue("productId", src.productId()) .hasFieldOrPropertyWithValue("productName", src.productName()) @@ -38,12 +39,12 @@ void testCheckoutItemPostVmToModel_convertToCorrectCheckoutItem(){ @Test void testCheckoutPostVmToModel_convertToCorrectCheckout(){ - // set up + CheckoutPostVm checkoutPostVm = Instancio.of(CheckoutPostVm.class) .create(); - // run + var res = checkoutMapper.toModel(checkoutPostVm); - // assert + Assertions.assertThat(res) .hasFieldOrPropertyWithValue("email", checkoutPostVm.email()) .hasFieldOrPropertyWithValue("note", checkoutPostVm.note()) @@ -55,11 +56,11 @@ void testCheckoutPostVmToModel_convertToCorrectCheckout(){ @Test void testCheckoutToVm_convertToCheckoutVmCorrectly(){ - // set up + Checkout checkout = Instancio.create(Checkout.class); - // run + var res = checkoutMapper.toVm(checkout); - // assert + Assertions.assertThat(res).hasFieldOrPropertyWithValue("id", checkout.getId()) .hasFieldOrPropertyWithValue("email", checkout.getEmail()) .hasFieldOrPropertyWithValue("note", checkout.getNote()) @@ -70,11 +71,11 @@ void testCheckoutToVm_convertToCheckoutVmCorrectly(){ @Test void testCheckoutItemToVm_convertCheckoutItemCorrectly(){ - // set up + CheckoutItem checkoutItem = Instancio.create(CheckoutItem.class); - // run + var res = checkoutMapper.toVm(checkoutItem); - // assert + Assertions.assertThat(res) .hasFieldOrPropertyWithValue("id", checkoutItem.getId()) .hasFieldOrPropertyWithValue("productId", checkoutItem.getProductId()) diff --git a/order/src/test/java/com/yas/order/service/CartServiceTest.java b/order/src/test/java/com/yas/order/service/CartServiceTest.java new file mode 100644 index 0000000000..89f9f070cd --- /dev/null +++ b/order/src/test/java/com/yas/order/service/CartServiceTest.java @@ -0,0 +1,125 @@ +package com.yas.order.service; + +import static com.yas.order.utils.SecurityContextUtils.setUpSecurityContext; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.yas.order.config.ServiceUrlConfig; +import com.yas.order.model.enumeration.DeliveryMethod; +import com.yas.order.model.enumeration.DeliveryStatus; +import com.yas.order.model.enumeration.OrderStatus; +import com.yas.order.model.enumeration.PaymentStatus; +import com.yas.order.viewmodel.order.OrderItemVm; +import com.yas.order.viewmodel.order.OrderVm; +import java.math.BigDecimal; +import java.net.URI; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +class CartServiceTest { + + private RestClient restClient; + + private ServiceUrlConfig serviceUrlConfig; + + private CartService cartService; + + private RestClient.ResponseSpec responseSpec; + + private static final String CART_URL = "http://api.yas.local/cart"; + + @BeforeEach + void setUp() { + restClient = mock(RestClient.class); + serviceUrlConfig = mock(ServiceUrlConfig.class); + cartService = new CartService(restClient, serviceUrlConfig); + responseSpec = Mockito.mock(RestClient.ResponseSpec.class); + setUpSecurityContext("test"); + when(serviceUrlConfig.cart()).thenReturn(CART_URL); + } + + @Test + void testDeleteCartItem_ifNormalCase_shouldNoException() { + + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.cart()) + .path("/storefront/cart-item/multi-delete") + .queryParam("productIds", List.of(101L, 102L)) + .buildAndExpand() + .toUri(); + + + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.delete()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + + OrderVm order = getOrderVm(); + assertDoesNotThrow(() -> cartService.deleteCartItem(order)); + } + + private static @NotNull OrderVm getOrderVm() { + Set items = getOrderItemVms(); + + return new OrderVm( + 1L, + "customer@example.com", + null, + null, + "Please deliver between 9 AM and 5 PM", + 5.0f, + 10.0f, + 3, + new BigDecimal("89.97"), + new BigDecimal("5.00"), + "COUPON2024", + OrderStatus.PENDING, + DeliveryMethod.GRAB_EXPRESS, + DeliveryStatus.CANCELLED, + PaymentStatus.PENDING, + items + ); + } + + private static @NotNull Set getOrderItemVms() { + OrderItemVm item1 = new OrderItemVm( + 1L, + 101L, + "Product A", + 2, + new BigDecimal("29.99"), + "Note for Product A", + new BigDecimal("5.00"), + new BigDecimal("2.00"), + new BigDecimal("6.67"), + 1001L + ); + + OrderItemVm item2 = new OrderItemVm( + 2L, + 102L, + "Product B", + 1, + new BigDecimal("49.99"), + "Note for Product B", + new BigDecimal("10.00"), + new BigDecimal("5.00"), + new BigDecimal("10.00"), + 1001L + ); + Set items = new HashSet<>(); + items.add(item1); + items.add(item2); + return items; + } +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/service/CheckoutServiceTest.java b/order/src/test/java/com/yas/order/service/CheckoutServiceTest.java index 2e83117444..df1092f879 100644 --- a/order/src/test/java/com/yas/order/service/CheckoutServiceTest.java +++ b/order/src/test/java/com/yas/order/service/CheckoutServiceTest.java @@ -24,6 +24,7 @@ @ExtendWith(SpringExtension.class) @SpringBootTest(classes = {CheckoutMapperImpl.class, CheckoutService.class}) class CheckoutServiceTest { + @MockBean CheckoutRepository checkoutRepository; @MockBean @@ -65,11 +66,11 @@ void setUp() { @Test void createCheckout() { - // set up + when(checkoutRepository.save(any())).thenReturn(checkoutCreated); - // run + var res = checkoutService.createCheckout(checkoutPostVm); - // assert + assertThat(res) .hasFieldOrPropertyWithValue("id", checkoutId) .hasFieldOrPropertyWithValue("email", checkoutPostVm.email()) diff --git a/order/src/test/java/com/yas/order/service/CustomerServiceTest.java b/order/src/test/java/com/yas/order/service/CustomerServiceTest.java new file mode 100644 index 0000000000..9e01652228 --- /dev/null +++ b/order/src/test/java/com/yas/order/service/CustomerServiceTest.java @@ -0,0 +1,75 @@ +package com.yas.order.service; + +import static com.yas.order.utils.SecurityContextUtils.setUpSecurityContext; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.yas.order.config.ServiceUrlConfig; +import com.yas.order.viewmodel.customer.CustomerVm; +import java.net.URI; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +class CustomerServiceTest { + + private RestClient restClient; + + private ServiceUrlConfig serviceUrlConfig; + + private CustomerService customerService; + + private RestClient.ResponseSpec responseSpec; + + private static final String CUSTOMER_URL = "http://api.yas.local/customer"; + + @BeforeEach + void setUp() { + restClient = mock(RestClient.class); + serviceUrlConfig = mock(ServiceUrlConfig.class); + customerService = new CustomerService(restClient, serviceUrlConfig); + responseSpec = Mockito.mock(RestClient.ResponseSpec.class); + setUpSecurityContext("test"); + when(serviceUrlConfig.customer()).thenReturn(CUSTOMER_URL); + } + + @Test + void testGetCustomer_ifNormalCase_returnCustomerVm() { + + final URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.customer()) + .path("/storefront/customer/profile") + .buildAndExpand() + .toUri(); + + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.get()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + + CustomerVm customer = new CustomerVm( + "john_doe", + "john.doe@example.com", + "John", + "Doe" + ); + when(responseSpec.body(CustomerVm.class)) + .thenReturn(customer); + + CustomerVm result = customerService.getCustomer(); + + assertNotNull(result); + assertThat(result.username()).isEqualTo("john_doe"); + assertThat(result.email()).isEqualTo("john.doe@example.com"); + assertThat(result.firstName()).isEqualTo("John"); + assertThat(result.lastName()).isEqualTo("Doe"); + + } + +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/service/OrderServiceTest.java b/order/src/test/java/com/yas/order/service/OrderServiceTest.java deleted file mode 100644 index c33e61d9ed..0000000000 --- a/order/src/test/java/com/yas/order/service/OrderServiceTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.yas.order.service; - -import com.yas.order.OrderApplication; -import com.yas.order.model.Order; -import com.yas.order.model.OrderItem; -import com.yas.order.repository.OrderItemRepository; -import com.yas.order.repository.OrderRepository; -import com.yas.order.viewmodel.order.OrderItemPostVm; -import com.yas.order.viewmodel.order.OrderPostVm; -import com.yas.order.viewmodel.order.OrderVm; -import com.yas.order.viewmodel.orderaddress.OrderAddressPostVm; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; - -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; - -@SpringBootTest(classes = OrderApplication.class) -class OrderServiceTest { - - @MockBean - private ProductService productService; - @MockBean - private CartService cartService; - @Autowired - private OrderItemRepository orderItemRepository; - @Autowired - private OrderRepository orderRepository; - @Autowired - private OrderService orderService; - private OrderItemPostVm orderItemPostVm; - private OrderAddressPostVm orderAddressPostVm; - private OrderPostVm orderPostVm; - - - @BeforeEach - void setUp() { - orderItemPostVm = OrderItemPostVm.builder() - .productId(1L).productName("abc") - .quantity(1).productPrice(BigDecimal.TEN) - .discountAmount(BigDecimal.ONE).taxAmount(BigDecimal.ONE).taxPercent(BigDecimal.ONE) - .build(); - orderAddressPostVm = OrderAddressPostVm.builder() - .contactName("contactName").phone("phone").addressLine1("addressLine1").addressLine2("addressLine2") - .city("city").zipCode("zipCode").districtId(1L).districtName("districtName") - .stateOrProvinceId(1L).stateOrProvinceName("stateOrProvinceName") - .countryId(1L).countryName("countryName") - .build(); - - orderPostVm = OrderPostVm.builder() - .checkoutId("1").email("abc@gmail.com") - .orderItemPostVms(Arrays.asList(orderItemPostVm)) - .billingAddressPostVm(orderAddressPostVm) - .shippingAddressPostVm(orderAddressPostVm) - .build(); - } - - @AfterEach - void tearDown() { - orderItemRepository.deleteAll(); - orderRepository.deleteAll(); - } - - @Test - void testCreateOrder_successful() { - - OrderVm orderVm = orderService.createOrder(orderPostVm); - - Optional orderOptional = orderRepository.findById(orderVm.id()); - assertTrue(orderOptional.isPresent()); - Order orderDB = orderOptional.get(); - assertEquals("abc@gmail.com", orderDB.getEmail()); - assertEquals(1, orderDB.getOrderItems().size()); - assertEquals("abc", orderDB.getOrderItems().stream().findFirst().get().getProductName()); - } - - @Test - void testCreateOrder_RemoteServiceThrowsException_RollbackOrder() { - doThrow(new RuntimeException()).when(productService).subtractProductStockQuantity(any(OrderVm.class)); - try { - orderService.createOrder(orderPostVm); - } catch (Exception e) { - - } - List orders = orderRepository.findAll(); - assertEquals(0, orders.size()); - List orderItems = orderItemRepository.findAll(); - assertEquals(0, orderItems.size()); - } - -} diff --git a/order/src/test/java/com/yas/order/service/TaxServiceTest.java b/order/src/test/java/com/yas/order/service/TaxServiceTest.java new file mode 100644 index 0000000000..0be423a261 --- /dev/null +++ b/order/src/test/java/com/yas/order/service/TaxServiceTest.java @@ -0,0 +1,69 @@ +package com.yas.order.service; + +import static com.yas.order.utils.SecurityContextUtils.setUpSecurityContext; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.yas.order.config.ServiceUrlConfig; +import java.net.URI; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +class TaxServiceTest { + + private RestClient restClient; + + private ServiceUrlConfig serviceUrlConfig; + + private TaxService taxService; + + private RestClient.ResponseSpec responseSpec; + + private static final String TAX_URL = "http://api.yas.local/tax"; + + @BeforeEach + void setUp() { + restClient = mock(RestClient.class); + serviceUrlConfig = mock(ServiceUrlConfig.class); + taxService = new TaxService(restClient, serviceUrlConfig); + responseSpec = Mockito.mock(RestClient.ResponseSpec.class); + setUpSecurityContext("test"); + when(serviceUrlConfig.tax()).thenReturn(TAX_URL); + } + + + @Test + void testGetTaxPercentByAddress_ifNormalCase_returnCustomerVm() { + + Long taxClassId = 1L; + Long countryId = 2L; + Long stateOrProvinceId = 3L; + String zipCode = "TEST"; + + URI url = UriComponentsBuilder.fromHttpUrl(serviceUrlConfig.tax()) + .path("/backoffice/tax-rates/tax-percent") + .queryParam("taxClassId", taxClassId) + .queryParam("countryId", countryId) + .queryParam("stateOrProvinceId", stateOrProvinceId) + .queryParam("zipCode", zipCode) + .build().toUri(); + + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.get()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + when(responseSpec.body(Double.class)) + .thenReturn(1.1); + + Double result = taxService.getTaxPercentByAddress(taxClassId, + countryId, stateOrProvinceId, zipCode); + + assertThat(result).isEqualTo(1.1); + } +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/utils/AuthenticationUtilsTest.java b/order/src/test/java/com/yas/order/utils/AuthenticationUtilsTest.java new file mode 100644 index 0000000000..bd24a42ae2 --- /dev/null +++ b/order/src/test/java/com/yas/order/utils/AuthenticationUtilsTest.java @@ -0,0 +1,29 @@ +package com.yas.order.utils; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; + +class AuthenticationUtilsTest { + + @Test + void testGetCurrentUserId_existsCurrentUserId_returnCurrentUserId() { + + JwtAuthenticationToken auth = mock(JwtAuthenticationToken.class); + Jwt jwt = mock(Jwt.class); + when(auth.getToken()).thenReturn(jwt); + when(jwt.getSubject()).thenReturn("testUserId"); + SecurityContext securityContext = mock(SecurityContext.class); + when(securityContext.getAuthentication()).thenReturn(auth); + SecurityContextHolder.setContext(securityContext); + + String au = AuthenticationUtils.getCurrentUserId(); + assertEquals("testUserId", au); + } +} \ No newline at end of file diff --git a/order/src/test/java/com/yas/order/utils/SecurityContextUtils.java b/order/src/test/java/com/yas/order/utils/SecurityContextUtils.java new file mode 100644 index 0000000000..2b80ac64f1 --- /dev/null +++ b/order/src/test/java/com/yas/order/utils/SecurityContextUtils.java @@ -0,0 +1,27 @@ +package com.yas.order.utils; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; + +public class SecurityContextUtils { + + private SecurityContextUtils() { + } + + public static void setUpSecurityContext(String userName) { + Authentication auth = mock(Authentication.class); + when(auth.getName()).thenReturn(userName); + Jwt jwt = mock(Jwt.class); + when(auth.getPrincipal()).thenReturn(jwt); + when(jwt.getTokenValue()).thenReturn("token"); + SecurityContext securityContext = mock(SecurityContext.class); + when(securityContext.getAuthentication()).thenReturn(auth); + SecurityContextHolder.setContext(securityContext); + } + +} diff --git a/payment/src/main/java/com/yas/payment/service/OrderService.java b/payment/src/main/java/com/yas/payment/service/OrderService.java index 8896264efe..feb51463b3 100644 --- a/payment/src/main/java/com/yas/payment/service/OrderService.java +++ b/payment/src/main/java/com/yas/payment/service/OrderService.java @@ -34,7 +34,9 @@ public Long updateCheckoutStatus(CapturedPayment capturedPayment) { return restClient.put() .uri(url) - .body(checkoutStatusVm).retrieve().body(Long.class); + .body(checkoutStatusVm) + .retrieve() + .body(Long.class); } @Retry(name = "restApi") diff --git a/payment/src/main/java/com/yas/payment/viewmodel/CapturedPayment.java b/payment/src/main/java/com/yas/payment/viewmodel/CapturedPayment.java index a013db72c3..10fdf7dc4e 100644 --- a/payment/src/main/java/com/yas/payment/viewmodel/CapturedPayment.java +++ b/payment/src/main/java/com/yas/payment/viewmodel/CapturedPayment.java @@ -1,6 +1,5 @@ package com.yas.payment.viewmodel; -import com.yas.payment.model.Payment; import com.yas.payment.model.enumeration.PaymentMethod; import com.yas.payment.model.enumeration.PaymentStatus; import java.math.BigDecimal; @@ -16,17 +15,4 @@ public record CapturedPayment( PaymentMethod paymentMethod, PaymentStatus paymentStatus, String failureMessage) { - public static CapturedPayment fromModel(Payment payment) { - return CapturedPayment.builder() - .amount(payment.getAmount()) - .paymentFee(payment.getPaymentFee()) - .checkoutId(payment.getCheckoutId()) - .orderId(payment.getOrderId()) - .gatewayTransactionId(payment.getGatewayTransactionId()) - .paymentMethod(payment.getPaymentMethod()) - .paymentStatus(payment.getPaymentStatus()) - .failureMessage(payment.getFailureMessage()) - .build(); - } - } \ No newline at end of file diff --git a/payment/src/test/java/com/yas/payment/service/OrderServiceTest.java b/payment/src/test/java/com/yas/payment/service/OrderServiceTest.java new file mode 100644 index 0000000000..c7b485da37 --- /dev/null +++ b/payment/src/test/java/com/yas/payment/service/OrderServiceTest.java @@ -0,0 +1,107 @@ +package com.yas.payment.service; + +import static com.yas.payment.util.SecurityContextUtils.setUpSecurityContext; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.yas.payment.config.ServiceUrlConfig; +import com.yas.payment.model.enumeration.PaymentMethod; +import com.yas.payment.model.enumeration.PaymentStatus; +import com.yas.payment.viewmodel.CapturedPayment; +import com.yas.payment.viewmodel.CheckoutStatusVm; +import com.yas.payment.viewmodel.PaymentOrderStatusVm; +import java.math.BigDecimal; +import java.net.URI; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +class OrderServiceTest { + + private RestClient restClient; + + private ServiceUrlConfig serviceUrlConfig; + + private OrderService orderService; + + private RestClient.ResponseSpec responseSpec; + + private static final String ORDER_URL = "http://api.yas.local/order"; + + @BeforeEach + void setUp() { + restClient = mock(RestClient.class); + serviceUrlConfig = mock(ServiceUrlConfig.class); + orderService = new OrderService(restClient, serviceUrlConfig); + responseSpec = Mockito.mock(RestClient.ResponseSpec.class); + setUpSecurityContext("test"); + when(serviceUrlConfig.order()).thenReturn(ORDER_URL); + } + + @Test + void testUpdateCheckoutStatus_whenNormalCase_returnLong() { + + CapturedPayment payment = CapturedPayment.builder() + .orderId(12345L) + .checkoutId("checkout-1234") + .amount(new BigDecimal("99.99")) + .paymentFee(new BigDecimal("2.50")) + .gatewayTransactionId("txn-67890") + .paymentMethod(PaymentMethod.COD) + .paymentStatus(PaymentStatus.COMPLETED) + .failureMessage(null) + .build(); + + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.order()) + .path("/storefront/checkouts/status") + .buildAndExpand() + .toUri(); + + RestClient.RequestBodyUriSpec requestBodyUriSpec = mock(RestClient.RequestBodyUriSpec.class); + when(restClient.put()).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.uri(url)).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.body(any(CheckoutStatusVm.class))).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.retrieve()).thenReturn(responseSpec); + when(responseSpec.body(Long.class)).thenReturn(1L); + + Long result = orderService.updateCheckoutStatus(payment); + + assertThat(result).isEqualTo(1L); + + } + + @Test + void testUpdateOrderStatus_whenNormalCase_returnPaymentOrderStatusVm() { + + PaymentOrderStatusVm statusVm = PaymentOrderStatusVm.builder() + .orderId(123456L) + .orderStatus("COMPLETED") + .paymentId(78910L) + .paymentStatus("SUCCESS") + .build(); + + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.order()) + .path("/storefront/orders/status") + .buildAndExpand() + .toUri(); + + RestClient.RequestBodyUriSpec requestBodyUriSpec = mock(RestClient.RequestBodyUriSpec.class); + when(restClient.put()).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.uri(url)).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.body(statusVm)).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.retrieve()).thenReturn(responseSpec); + when(responseSpec.body(PaymentOrderStatusVm.class)).thenReturn(statusVm); + + PaymentOrderStatusVm result = orderService.updateOrderStatus(statusVm); + assertThat(result.orderId()).isEqualTo(123456L); + assertThat(result.orderStatus()).isEqualTo("COMPLETED"); + assertThat(result.paymentId()).isEqualTo(78910L); + assertThat(result.paymentStatus()).isEqualTo("SUCCESS"); + } +} \ No newline at end of file diff --git a/payment/src/test/java/com/yas/payment/serivce/PaymentProviderServiceTest.java b/payment/src/test/java/com/yas/payment/service/PaymentProviderServiceTest.java similarity index 97% rename from payment/src/test/java/com/yas/payment/serivce/PaymentProviderServiceTest.java rename to payment/src/test/java/com/yas/payment/service/PaymentProviderServiceTest.java index 9cbebbf33c..ac61fa8ef0 100644 --- a/payment/src/test/java/com/yas/payment/serivce/PaymentProviderServiceTest.java +++ b/payment/src/test/java/com/yas/payment/service/PaymentProviderServiceTest.java @@ -1,20 +1,17 @@ -package com.yas.payment.serivce; +package com.yas.payment.service; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import com.yas.payment.exception.NotFoundException; import com.yas.payment.model.PaymentProvider; import com.yas.payment.repository.PaymentProviderRepository; -import com.yas.payment.service.PaymentProviderService; import com.yas.payment.viewmodel.PaymentProviderVm; - import java.util.List; import java.util.Optional; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; diff --git a/payment/src/test/java/com/yas/payment/serivce/PaymentServiceTest.java b/payment/src/test/java/com/yas/payment/service/PaymentServiceTest.java similarity index 97% rename from payment/src/test/java/com/yas/payment/serivce/PaymentServiceTest.java rename to payment/src/test/java/com/yas/payment/service/PaymentServiceTest.java index 896f6c5581..d0f4aa2391 100644 --- a/payment/src/test/java/com/yas/payment/serivce/PaymentServiceTest.java +++ b/payment/src/test/java/com/yas/payment/service/PaymentServiceTest.java @@ -1,22 +1,21 @@ -package com.yas.payment.serivce; +package com.yas.payment.service; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.assertj.core.api.Assertions.assertThat; -import org.mockito.ArgumentCaptor; + import com.yas.payment.model.Payment; import com.yas.payment.model.enumeration.PaymentMethod; -import com.yas.payment.repository.PaymentRepository; -import com.yas.payment.service.OrderService; -import com.yas.payment.service.PaymentService; import com.yas.payment.model.enumeration.PaymentStatus; +import com.yas.payment.repository.PaymentRepository; import com.yas.payment.viewmodel.CapturedPayment; import com.yas.payment.viewmodel.PaymentOrderStatusVm; import java.math.BigDecimal; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; diff --git a/payment/src/test/java/com/yas/payment/util/SecurityContextUtils.java b/payment/src/test/java/com/yas/payment/util/SecurityContextUtils.java new file mode 100644 index 0000000000..c6951422d1 --- /dev/null +++ b/payment/src/test/java/com/yas/payment/util/SecurityContextUtils.java @@ -0,0 +1,27 @@ +package com.yas.payment.util; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; + +public class SecurityContextUtils { + + private SecurityContextUtils() { + } + + public static void setUpSecurityContext(String userName) { + Authentication auth = mock(Authentication.class); + when(auth.getName()).thenReturn(userName); + Jwt jwt = mock(Jwt.class); + when(auth.getPrincipal()).thenReturn(jwt); + when(jwt.getTokenValue()).thenReturn("token"); + SecurityContext securityContext = mock(SecurityContext.class); + when(securityContext.getAuthentication()).thenReturn(auth); + SecurityContextHolder.setContext(securityContext); + } + +} diff --git a/promotion/src/it/java/com/yas/promotion/config/IntegrationTestConfiguration.java b/promotion/src/it/java/com/yas/promotion/config/IntegrationTestConfiguration.java new file mode 100644 index 0000000000..0ae9843086 --- /dev/null +++ b/promotion/src/it/java/com/yas/promotion/config/IntegrationTestConfiguration.java @@ -0,0 +1,30 @@ +package config; + +import dasniko.testcontainers.keycloak.KeycloakContainer; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.testcontainers.containers.PostgreSQLContainer; + +@TestConfiguration +public class IntegrationTestConfiguration { + + @Bean(destroyMethod = "stop") + public PostgreSQLContainer postgresContainer() { + return new PostgreSQLContainer<>("postgres:16") + .withReuse(true); + } + + @Bean(destroyMethod = "stop") + public KeycloakContainer keycloakContainer(DynamicPropertyRegistry registry) { + KeycloakContainer keycloak = new KeycloakContainer() + .withRealmImportFiles("/test-realm.json") + .withReuse(true); + + registry.add("spring.security.oauth2.resourceserver.jwt.issuer-uri", + () -> keycloak.getAuthServerUrl() + "/realms/quarkus"); + registry.add("spring.security.oauth2.resourceserver.jwt.jwk-set-uri", + () -> keycloak.getAuthServerUrl() + "/realms/quarkus/protocol/openid-connect/certs"); + return keycloak; + } +} diff --git a/promotion/src/it/java/com/yas/promotion/service/PromotionServiceIT.java b/promotion/src/it/java/com/yas/promotion/service/PromotionServiceIT.java new file mode 100644 index 0000000000..db7c5442a1 --- /dev/null +++ b/promotion/src/it/java/com/yas/promotion/service/PromotionServiceIT.java @@ -0,0 +1,246 @@ +package com.yas.promotion.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.when; + +import com.yas.promotion.PromotionApplication; +import com.yas.promotion.exception.BadRequestException; +import com.yas.promotion.exception.DuplicatedException; +import com.yas.promotion.exception.NotFoundException; +import com.yas.promotion.model.Promotion; +import com.yas.promotion.model.PromotionUsage; +import com.yas.promotion.model.enumeration.ApplyTo; +import com.yas.promotion.repository.PromotionRepository; +import com.yas.promotion.repository.PromotionUsageRepository; +import com.yas.promotion.utils.Constants; +import com.yas.promotion.viewmodel.PromotionDetailVm; +import com.yas.promotion.viewmodel.PromotionListVm; +import com.yas.promotion.viewmodel.PromotionPostVm; +import com.yas.promotion.viewmodel.PromotionPutVm; +import config.IntegrationTestConfiguration; +import java.time.Instant; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +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.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +@SpringBootTest(classes = PromotionApplication.class) +@Import(IntegrationTestConfiguration.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class PromotionServiceIT { + + @Autowired + private PromotionRepository promotionRepository; + @Autowired + private PromotionService promotionService; + @MockBean + private ProductService productService; + @Autowired + private PromotionUsageRepository promotionUsageRepository; + + private Promotion promotion1; + private Promotion wrongRangeDatePromotion; + private PromotionPostVm promotionPostVm; + + @BeforeEach + void setUp() { + promotion1 = Promotion.builder() + .name("Promotion 1") + .slug("promotion-1") + .description("Description 1") + .couponCode("code1") + .discountAmount(100L) + .discountPercentage(10L) + .isActive(true) + .startDate(Instant.now()) + .endDate(Instant.now().plusSeconds(2592000)) + .applyTo(ApplyTo.CATEGORY) + .build(); + promotion1 = promotionRepository.save(promotion1); + + Promotion promotion2 = Promotion.builder() + .name("Promotion 2") + .slug("promotion-2") + .description("Description 2") + .couponCode("code2") + .discountAmount(200L) + .discountPercentage(20L) + .isActive(false) + .applyTo(ApplyTo.CATEGORY) + .startDate(Instant.now().minusSeconds(2592000)) + .endDate(Instant.now().plusSeconds(5184000)) + .build(); + promotionRepository.save(promotion2); + + wrongRangeDatePromotion = Promotion.builder() + .name("Wrong date") + .slug("wrong-date") + .description("Promotion with invalid date range") + .couponCode("codeWrong") + .discountAmount(200L) + .discountPercentage(20L) + .isActive(false) + .startDate(Instant.now().minusSeconds(2592000)) + .endDate(Instant.now().minusSeconds(5184000)) + .build(); + wrongRangeDatePromotion = promotionRepository.save(wrongRangeDatePromotion); + } + + @AfterEach + void tearDown() { + promotionUsageRepository.deleteAll(); + promotionRepository.deleteAll(); + } + + @Test + void createPromotion_ThenSuccess() { + promotionPostVm = PromotionPostVm.builder() + .name("Promotion 3") + .slug("promotion-3") + .description("Description 3") + .couponCode("code3") + .discountAmount(300L) + .discountPercentage(30L) + .isActive(true) + .startDate(Instant.now().plusSeconds(5184000)) + .endDate(Instant.now().plusSeconds(7776000)) + .applyTo(ApplyTo.PRODUCT) + .productIds(List.of(1L, 2L, 3L)) + .build(); + + PromotionDetailVm result = promotionService.createPromotion(promotionPostVm); + assertEquals(promotionPostVm.getSlug(), result.slug()); + assertEquals(promotionPostVm.getName(), result.name()); + assertEquals(true, result.isActive()); + } + + @Test + void createPromotion_WhenExistedSlug_ThenDuplicatedExceptionThrown() { + promotionPostVm = PromotionPostVm.builder() + .slug(promotion1.getSlug()) + .build(); + assertThrows(DuplicatedException.class, () -> promotionService.createPromotion(promotionPostVm), + String.format(Constants.ErrorCode.SLUG_ALREADY_EXITED, promotionPostVm.getSlug())); + } + + @Test + void createPromotion_WhenEndDateBeforeStartDate_ThenDateRangeExceptionThrown() { + promotionPostVm = PromotionPostVm.builder() + .endDate(wrongRangeDatePromotion.getEndDate()) + .startDate(wrongRangeDatePromotion.getStartDate()) + .build(); + + BadRequestException exception = assertThrows(BadRequestException.class, () -> + promotionService.createPromotion(promotionPostVm) + ); + assertEquals(String.format(Constants.ErrorCode.DATE_RANGE_INVALID), exception.getMessage()); + } + + @Test + void getPromotionLists_existsPromotions_ThenPromotionListVm() { + + PromotionListVm result = getPromotionListVm(); + assertEquals(2, result.promotionDetailVmList().size()); + PromotionDetailVm promotionDetailVm = result.promotionDetailVmList().getFirst(); + assertEquals("promotion-1", promotionDetailVm.slug()); + } + + @Test + void testUpdatePromotion_whenNormalCase_updatePromotion() { + + when(productService.getCategoryByIds(anyList())).thenReturn(List.of()); + PromotionListVm result = getPromotionListVm(); + PromotionDetailVm promotionDetailVm = result.promotionDetailVmList().getFirst(); + + PromotionPutVm promotionPutVm = PromotionPutVm.builder() + .id(promotionDetailVm.id()) + .name("Promotion 1") + .slug("promotion-1") + .description("Description 123") + .couponCode("code1") + .discountAmount(100L) + .discountPercentage(20L) + .isActive(true) + .startDate(Instant.now().plusSeconds(5184000)) + .endDate(Instant.now().plusSeconds(7776000)) + .applyTo(ApplyTo.PRODUCT) + .productIds(List.of(1L, 2L, 3L)) + .build(); + + promotionService.updatePromotion(promotionPutVm); + + PromotionListVm actual = getPromotionListVm(); + assertEquals(2, result.promotionDetailVmList().size()); + + PromotionDetailVm promotionDetailVmActual = actual.promotionDetailVmList().getFirst(); + assertEquals("Description 123", promotionDetailVmActual.description()); + } + + @Test + void testUpdatePromotion_whenPromotionIsEmpty_throwNotFoundException() { + PromotionPutVm promotionPutVm = PromotionPutVm.builder() + .id(433L) + .name("Promotion 1") + .endDate(Instant.now().plusSeconds(7776000)) + .applyTo(ApplyTo.PRODUCT) + .productIds(List.of(1L, 2L, 3L)) + .build(); + + NotFoundException exception = assertThrows(NotFoundException.class, + () -> promotionService.updatePromotion(promotionPutVm)); + assertEquals("Promotion 433 is not found", exception.getMessage()); + + } + + @Test + void testDeletePromotion_normalCase_deletePromotion() { + + PromotionListVm result = getPromotionListVm(); + PromotionDetailVm promotionDetailVm = result.promotionDetailVmList().getFirst(); + + promotionService.deletePromotion(promotionDetailVm.id()); + + PromotionListVm actual = getPromotionListVm(); + assertEquals(1, actual.promotionDetailVmList().size()); + assertNotEquals(promotionDetailVm.id(), actual.promotionDetailVmList().getFirst().id()); + + } + + @Test + void testDeletePromotion_existsPromotionUsageByPromotionId_throwBadRequestException() { + + PromotionListVm result = getPromotionListVm(); + PromotionDetailVm promotionDetailVm = result.promotionDetailVmList().getFirst(); + Promotion promotion = new Promotion(); + promotion.setId(promotionDetailVm.id()); + + PromotionUsage promotionUsage = PromotionUsage.builder() + .promotion(promotion) + .productId(1L) + .userId("user-id") + .orderId(1L) + .build(); + + promotionUsageRepository.save(promotionUsage); + Long promotionId = promotionDetailVm.id(); + + BadRequestException exception = assertThrows(BadRequestException.class, + () -> promotionService.deletePromotion(promotionId)); + assertEquals("Can't delete promotion " + promotionId + " because it is in use", exception.getMessage()); + } + + private PromotionListVm getPromotionListVm() { + return promotionService.getPromotions(0, 5, + "Promotion", "code", + Instant.now().minusSeconds(10368000), Instant.now().plusSeconds(10368000)); + } + +} diff --git a/promotion/src/it/resources/application.properties b/promotion/src/it/resources/application.properties new file mode 100644 index 0000000000..297601e81d --- /dev/null +++ b/promotion/src/it/resources/application.properties @@ -0,0 +1,15 @@ +# Setting Spring context path & port +server.port=8092 +server.servlet.context-path=/promotion + +spring.application.name=promotion + +spring.jpa.hibernate.ddl-auto=update +spring.liquibase.enabled=false + +# Setting Spring profile +spring.profiles.active=test + +spring.security.oauth2.resourceserver.jwt.issuer-uri=test +springdoc.oauthflow.authorization-url=test +springdoc.oauthflow.token-url=test diff --git a/promotion/src/it/resources/logback-spring.xml b/promotion/src/it/resources/logback-spring.xml new file mode 100644 index 0000000000..e7d52d7271 --- /dev/null +++ b/promotion/src/it/resources/logback-spring.xml @@ -0,0 +1,16 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/promotion/src/it/resources/mockito-extensions/org.mockito.plugins.MockMaker b/promotion/src/it/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..be144a36cb --- /dev/null +++ b/promotion/src/it/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1,2 @@ +mock-maker-inline + diff --git a/promotion/src/it/resources/test-realm.json b/promotion/src/it/resources/test-realm.json new file mode 100644 index 0000000000..ecf799f97d --- /dev/null +++ b/promotion/src/it/resources/test-realm.json @@ -0,0 +1,1857 @@ +{ + "id" : "quarkus", + "realm" : "quarkus", + "notBefore" : 0, + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 300, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "enabled" : true, + "sslRequired" : "external", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ + { + "id": "f2da71cd-654f-4beb-8ec8-fa78d6fc1219", + "name": "default-roles-yas", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ] + }, + "clientRole": false, + "containerId": "Yas", + "attributes": {} + }, + { + "id": "eadee165-c7b4-4508-bf60-937580c5d987", + "name": "ADMIN", + "composite": false, + "clientRole": false, + "containerId": "Yas", + "attributes": {} + }, + { + "id" : "5ae801de-cd65-42c1-ac5e-3b051abadcff", + "name" : "admin", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + }, { + "id" : "2bca19e3-c333-41fb-8549-526536f039fb", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + }, { + "id" : "c924843b-38ab-4c85-871c-86f6e0b47500", + "name" : "user", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + }, { + "id" : "589c3954-acfd-4689-815d-d3e7ce172045", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "quarkus", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "1c1db47d-3e9f-4bcb-aa37-b5b4b0d67942", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "f3deb521-8e02-4496-a242-e015c32e42ad", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "e9f35eb2-f3e6-41ac-aac9-0f540fbb1f2d", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "83d46ffc-8744-4fd6-a407-75098529adb7", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "23f29143-b35a-4f3d-88bf-b1ac603ca86f", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "ece87aaa-bbb1-48dc-b663-48a36dbb732a", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "9b9d045d-2884-41ae-9a2a-484907ff664d", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "89f6649a-1d40-4fab-a005-b892d6589764", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "8414a9d2-4ae1-45bb-8746-d0d857067f97", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "e02cdfef-d0ec-4e34-9457-76294b42adc5", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "85cd6885-cb73-4ac8-93ec-8fc4d7c75999", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "c8214f22-687a-45cb-a575-dea31b92ebe8", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "4e01ff83-6d49-48e6-bbc1-37dff1bf876b", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "0dc9eda3-37dd-46d5-8130-39046f3bcaf9", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "a39504b0-e679-4e59-ab14-3c7727a4f5c3", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "e1a6e15d-4b77-4a77-9348-bfc3190e2a2d", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "3f29e90a-1f05-4f8e-82b6-32a39127d73b", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "view-identity-providers", "manage-identity-providers", "manage-authorization", "view-events", "manage-realm", "create-client", "manage-clients", "view-authorization", "query-realms", "query-clients", "view-clients", "manage-users", "view-realm", "impersonation", "query-groups", "view-users", "query-users", "manage-events" ] + } + }, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "7b3322f1-7bc8-456a-ab1f-9f06a4af9311", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + }, { + "id" : "0bb5515b-adc3-495e-8e38-d34bac2162a6", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "quarkus-service" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "7a996641-0139-4e46-9cf8-96273e57d0ba", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "d4c8f765-b8b3-44fa-a99c-4001172f98f3", + "attributes" : { } + } ], + "account" : [ { + "id" : "4f26a889-000a-41ee-b3cc-c6db5a344833", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "04c2755b-e926-467b-983e-3eb3bb23e5a5", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "ee3d20f8-544f-49d9-b98c-0e46589c67f1", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "3b991fa9-2469-402a-a249-fb237cf6f364", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "79fdb572-7eb9-4236-adc1-61d95d9e10d2", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "66ddea7c-27a7-4ab9-bc0b-bf404ab84199", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + }, { + "id" : "dad36647-a910-4b97-b8eb-4248dfc37252", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "attributes" : { } + } ] + } + }, + "groups" : [ ], + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ], + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "users" : [ { + "id" : "7d40c686-612a-4b49-93fd-e28244f40136", + "createdTimestamp" : 1617800939748, + "username" : "admin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "Admin", + "lastName" : "Admin", + "email" : "admin@localhost", + "credentials" : [ { + "id" : "b68a1141-f42e-4cba-8c7a-97a47fb81857", + "type" : "password", + "createdDate" : 1617800952774, + "secretData" : "{\"value\":\"5VL5vW+2wIu0SCW7Fy5EzktX5X6LkiDNjCp2MLrdudF9EiR3rs12dhGTHs5wyXlK9944I4e3iBsK01EVuzEXPw==\",\"salt\":\"6tTNIudRbWQhlZBB8vkjRg==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles": ["default-roles-yas", "ADMIN"], + "clientRoles" : { + "account" : [ "view-profile", "manage-account" ] + }, + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "af9b247a-ff16-424b-af38-e7473c16a406", + "createdTimestamp" : 1617800970630, + "username" : "john", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "John", + "lastName" : "Doe", + "email" : "john@localhost", + "credentials" : [ { + "id" : "e86c9af1-5e25-4918-bc70-457a3aade97b", + "type" : "password", + "createdDate" : 1617800978521, + "secretData" : "{\"value\":\"oMEimHrxfSIjQsi3bwdynWL3xUusgXK3YiaWV1bRtN+2yRFuPWDQ3UbeppxSH9DDJuI9euZuwFMsb3PUOgs78Q==\",\"salt\":\"8jLTvRKcWnSo8/Z5+vCG3A==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "user" ], + "clientRoles" : { + "account" : [ "view-profile", "manage-account" ] + }, + "notBefore" : 0, + "groups" : [ ] + } ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account" ] + } ] + }, + "clients" : [ { + "id" : "b2ef7463-a161-4bd7-a9d3-361633512bce", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/quarkus/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "46c49daf-fa62-4744-883d-d32e810cfb9c", + "defaultRoles" : [ "view-profile", "manage-account" ], + "redirectUris" : [ "/realms/quarkus/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "0e2c27dd-f217-4926-a575-4c59171f9f39", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/quarkus/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "134ac396-96f5-432a-8241-faf3de2711f6", + "redirectUris" : [ "/realms/quarkus/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "ed59083f-a6e7-41f5-8caf-c49dfa04b969", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "6f9a7a50-f05f-4833-8dba-2492a2a70b40", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "8caf9d87-7e94-4597-931a-4cb5357e72b2", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "d4c8f765-b8b3-44fa-a99c-4001172f98f3", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "590e533b-5a2d-4dd1-9419-d301f326cf0a", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "56443d41-f71f-490f-872c-5daa01b31a28", + "clientId" : "quarkus-service", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "secret", + "redirectUris" : [ "/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : true, + "authorizationServicesEnabled": true, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "saml.assertion.signature" : "false", + "saml.multivalued.roles" : "false", + "saml.force.post.binding" : "false", + "saml.encrypt" : "false", + "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens" : "false", + "saml.server.signature" : "false", + "saml.server.signature.keyinfo.ext" : "false", + "exclude.session.state.from.auth.response" : "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required" : "true", + "client_credentials.use_refresh_token" : "false", + "saml_force_name_id_format" : "false", + "saml.client.signature" : "false", + "tls.client.certificate.bound.access.tokens" : "false", + "saml.authnstatement" : "false", + "display.on.consent.screen" : "false", + "saml.onetimeuse.condition" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ], + "authorizationSettings": { + "allowRemoteResourceManagement": true, + "policyEnforcementMode": "ENFORCING", + "resources": [ + { + "name": "Admin Resource", + "ownerManagedAccess": false, + "attributes": {}, + "_id": "d2b855d4-61f6-4159-9b89-b0257ad380c9", + "uris": [ + "/admin/*" + ], + "icon_uri": "" + }, + { + "name": "User Resource", + "ownerManagedAccess": false, + "attributes": {}, + "_id": "6f589c2e-160c-487b-8e8c-8141dc441b2a", + "uris": [ + "/users/*" + ], + "icon_uri": "" + } + ], + "policies": [ + { + "id": "2aaaff19-710d-479d-80b8-ef57e4e258d8", + "name": "Any User Policy", + "description": "Any user granted with the user role can access something", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"user\",\"required\":false}]" + } + }, + { + "id": "43b4ae35-5fc4-45d7-b0a2-501e772ecb84", + "name": "Only Admins", + "description": "Only administrators can access", + "type": "role", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "roles": "[{\"id\":\"admin\",\"required\":false}]" + } + }, + { + "id": "06fc24d8-1f84-46f4-ae7b-e13a505195f1", + "name": "User Resource Permission", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "defaultResourceType": "", + "resources": "[\"User Resource\"]", + "applyPolicies": "[\"Any User Policy\"]" + } + }, + { + "id": "d75310e2-8b14-4c88-9148-2fa82220e30b", + "name": "Admin Resource Permission", + "description": "", + "type": "resource", + "logic": "POSITIVE", + "decisionStrategy": "UNANIMOUS", + "config": { + "resources": "[\"Admin Resource\"]", + "applyPolicies": "[\"Only Admins\"]" + } + } + ], + "scopes": [], + "decisionStrategy": "UNANIMOUS" + } + }, { + "id" : "752904b5-c4f5-473e-ba84-7d214afdf792", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "70fd3aa0-f353-4860-9a67-5eb86684e0a8", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "b720bc75-35bf-4dcd-a5a9-90d1267a3b04", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/quarkus/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "55fbb9e1-4410-48b7-b1ad-7b043144b859", + "redirectUris" : [ "/admin/quarkus/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "44e02e60-ae62-4b32-b20b-226565749528", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "0110b627-1823-4aa2-9c12-e25eb8bc1d24", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "14a58948-73a4-4679-ae93-93e7cf91f337", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "203f72b9-e269-4433-a1d6-5067a82e6029", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "e8d6fa1d-5d10-4388-a815-b8cc269cf521", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${profileScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "e0d1b63e-956f-43aa-8bf0-5331d2b6160c", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "dfa55ca4-9c69-4238-bebf-9bcc9144508e", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "bae556b2-5a2e-4eea-b5cb-717e0c4cbf5f", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "9a4b7133-a0f3-4043-884e-b9bf571c81d7", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "6164139c-c1f4-44bb-9c22-800e2d21ca09", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "527d79d0-1966-4b90-92f0-0b54c623d596", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "String" + } + }, { + "id" : "39655902-2b3a-4205-a8db-03ad38bb4df6", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "3e9b71e1-0829-4a57-80ff-09f2718abf13", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "d6f5b49a-df41-4fee-93ec-246e5202fdff", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "5a648f3a-07d2-4c8d-afe8-c1accb9b1187", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "b7e2d1ac-2517-4df1-b9a9-afb925339731", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "0c2ab3b5-f6c6-45d8-8894-3cf71dc6fb38", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "9e7b6084-7a84-4699-9b51-d619094f4ff9", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "61ab8691-6995-4d4f-8917-67093c8aedfb", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "183a7265-5d2a-41bd-baf0-dd376b366063", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "887b7325-71e4-4eac-a197-6948862cb928", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "7f540ab7-f7b6-41d7-b56c-5b63ec354abe", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "bf8af7d9-fff7-427e-880e-62ea16ab94e9", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "cd85be29-34ed-47e2-b0ce-2270f8061f09", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "abed9a36-8900-4eec-9d58-9528f6f284ac", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${phoneScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "ef60ce57-9cfa-449c-9624-f74a16944327", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "b3636e01-5cb1-4ce2-b08a-913f15bbc738", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "2036bd5e-f33d-442d-8ed0-6bf9a50ad45d", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${rolesScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "73ac1825-7ac3-40ad-8f38-b2620808b02f", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "0d0ca6ec-e6cc-425f-ba92-2ed4b7778faf", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + }, { + "id" : "aa5d7eab-30e5-49eb-a4fe-4ad425fffd64", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + }, { + "id" : "4c7b020d-ab2d-4cee-a9c1-26b5a28453df", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "9762fd5d-17bf-4666-b538-0adee5f584c3", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "92cb2a60-3a1f-4bf1-94b9-078e80cff964", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "1354aade-9a9f-41db-a462-f2071532fd6f", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "multivalued" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + }, { + "id" : "0e78dfa6-86dd-4960-a23b-44c3329df528", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins" ], + "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "a033e338-3cfe-4440-85dd-ec4a332742fd", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "66eb3397-e784-4b4d-8242-5385453197b7", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper" ] + } + }, { + "id" : "3e836a32-ff93-46e6-8e1f-7e320507388f", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "bad9c53c-6b7b-431f-a4f4-62970f9af1e2", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "174410e0-cd98-4a90-bfc3-68a8980b87e7", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "2b9ca142-85a0-448d-bde9-800f7823cac1", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "4271132b-929b-4b76-a94e-aeafa71715ec", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "6ab250a9-d27b-4c5c-8cdf-0b8adee370d4", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "e7f99358-99f3-4fb6-a65d-5771a0c07f38", + "name" : "hmac-generated", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "a7c0b05e-7852-492d-a712-30ce7c6e48a6" ], + "secret" : [ "gh6Ab3iAF2CiWam3ly0OZcwfMPRNn6s0lgqmn177iHBSebirfHRkahPjJGmGVHS9fmqRidaOV8v1YoxF0lhv5Q" ], + "priority" : [ "100" ], + "algorithm" : [ "HS256" ] + } + }, { + "id" : "30fe7115-b6e4-4ed8-b350-73a160895f4c", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEAnTsWCUKow1fwyn/p38MM7SfuS1KzDGGWPLcrt4r6Hy2vPG8G6psABbkA2+if5y+614vjLKaG2g33bU4OkoVOcGtISMN+Fc2J+i/Fd250PaLCe89uRzrHc2q+6bgMuvOnNtcOJqR+Y+Zrs34kG0izWe+dHTNrgav4WKbpKzAR3ZlCNIkVU81m2LG+u6MyQJpN3RiOaeBC/vtxCGHPO4BTHA4cCeXVd8P9Gczh5WqSH+Es5dQRxfLiWDLbV+BeAeDvJIhJq8yuLkjBBnq1w5TASVf8U+LsVVWCwUy/lDXDX7G2EVU+BRq9hfRPRkiXcN+CigZVr6b8JXdUH4Kh/PF2QwIDAQABAoIBAG1YLw4HnqgjW2DorjQgSLgRYgZeIAjHQR0+YZfGfgX61nhX2l6DpvNT4sYMtE+qAO1v6nAd64Bv4BfTBg1dydwir+VylxgAlik42cIiPZKzwz8pVc8RkK2ymcyeY7QMSMi5rKyxDvjYwSPV4LRczeYI3qH1JZnLh+3XPib7yiDqIQhMEPxxdOGzidwSwijTzVfOt5ltsk5T4ZCsGpWvoGnvNQYRlt4AdewGP0Mg0hacS21y5M6B1he+z9Tnb2/uIloGvEBHNCPsvn6qXmszoZhKH4FueP6cfgO4342jR8ksEhwlpgmAQ87B5zabMyRbstnazr1Am1dgCAQRto+xFXECgYEA3e8rqymsdVwnbjFsSv6K67SvnJdqFFHAcdzqeCoOsy0JBlb3ck9zvW/8R0dMx0YQ83dxlvKxCESOhroSHQ4P38N4t4CeOOSPhBnYFnfc3n75ckro1fp3WWL4Dq/oN63wiaNQCISz5HYdqXs9GXMVn5GRS8kr70qa3PrXY8RGa/sCgYEAtV1qcEoqMUVQGSYF3eWlXqTVn4RvonIg87Jw/dnaPnSUcy8+80+ipJiCInzRsZ+ApPNie+VStdg7mz0pDGkA9vqDX1SQYsp5XcCtq49Pt+Oc8woPowjY+rU8Us5v+BYM2RjAhO85+obsXkPchQsC+au6IODrA3awGHb5cuNyBFkCgYEAnbpqTbZLdAkvmNgVP+NR9hyvJlpSMOi9He9E0GwLkHn0TQYnzJz9A+h/4mShA4sfZvk/yGjpOpgGt2eskeu5im1Q8RG+4W5HNTps4eMEHTkerYThn5nnkqaM51tLba74IcnoinVNqJPtltMYZGrvNj3thnAOAn4CPAUmaShIaFsCgYAkWLpSEqruAOQShio61CEWHJarR1FQDutHq4U1eolgZuCxTNCi1lzT+7Ro0Pb9T+fqJtSf2899nf4kGFe3ovuMg5v8aOgexFEaVtj3PttNERKNKoEDvWwuok+akMCjyVd90pYSjhbifFO2eIcjKpfIDYBZwnmW0hxsaruHKMna0QKBgEYF8xk/XqDViV2a7C8byQNBXwFWzct+rcdj9yOMqdWl8XTBU7Tf2YojRKGjkpMHnrNbDCQPUYcKoIYZBWdkiufe5WTDU/3yLZjbMl+9jC9MQ3sXSZqWEqsdKDFZVFFXWNMxbmSPZMLWm3kWM0yxGg3e2il/NHpiNjssEz/toasC" ], + "certificate" : [ "MIICnTCCAYUCBgF4rE75SjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdxdWFya3VzMB4XDTIxMDQwNzEyMjc0MFoXDTMxMDQwNzEyMjkyMFowEjEQMA4GA1UEAwwHcXVhcmt1czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ07FglCqMNX8Mp/6d/DDO0n7ktSswxhljy3K7eK+h8trzxvBuqbAAW5ANvon+cvuteL4yymhtoN921ODpKFTnBrSEjDfhXNifovxXdudD2iwnvPbkc6x3Nqvum4DLrzpzbXDiakfmPma7N+JBtIs1nvnR0za4Gr+Fim6SswEd2ZQjSJFVPNZtixvrujMkCaTd0YjmngQv77cQhhzzuAUxwOHAnl1XfD/RnM4eVqkh/hLOXUEcXy4lgy21fgXgHg7ySISavMri5IwQZ6tcOUwElX/FPi7FVVgsFMv5Q1w1+xthFVPgUavYX0T0ZIl3DfgooGVa+m/CV3VB+CofzxdkMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACWVoMh1jB64LEiOzHrwDWeWDHRZMrb1TBcfC6ALjFDBako0AbSHxBqN6FJgN6C3BhzCBcI4LR6I8bpqGuZ9y9zE8hRj8oAtEAXnPdMSWsWEBBFdbSBDeBE9Q8jXJ5LCk+Iz/5HcPJTgUpkJdKmzIWqp1hI4zOb1+GZrERg04Ue+xP6DTCOZkcofA3twzqM0Eifig8UoSUlejUKXCISbcO39slcFNGbPDPsUNjWUgVG79TZExtF02KmbzEifh+aQi0jb3/d5gSPEOSW+n8CC/zW0woDZQ4ZhspDUeQyIafy0JPlgZljsWBbWpJ0ZJIiWVTWxO7T1ogiyFtLoX2sinJA==" ], + "priority" : [ "100" ] + } + }, { + "id" : "1d927d6c-779e-4fea-a2a4-a3dd194c1a8f", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "12395eb8-d68a-4272-b88e-3e2a2096e2e6" ], + "secret" : [ "uqAMrTEXiIXom7DjxnnWEw" ], + "priority" : [ "100" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "0b0bb974-6484-4dbc-bc0c-7a3ce27a1a2f", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "ALTERNATIVE", + "priority" : 20, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "b7f60e5e-94c8-4ede-ab61-ced8b2fea44a", + "alias" : "Authentication Options", + "description" : "Authentication options.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "basic-auth", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "basic-auth-otp", + "requirement" : "DISABLED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-spnego", + "requirement" : "DISABLED", + "priority" : 30, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "423fe6a4-3445-4731-8ac3-23e348b08743", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-otp-form", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "c60ff278-6c63-4d7e-ad1c-7c4e825199a6", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "d5bde955-3a6e-47d2-9289-fdd28e1d1c45", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-otp-form", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "2fc18574-8dc9-4a4f-9dbf-f7b221a978bc", + "alias" : "Handle Existing Account", + "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "REQUIRED", + "priority" : 20, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "306c3c73-3d32-44ce-8781-e2cde85d7823", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "reset-otp", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "ee1b35cd-1378-4d4d-b47b-f769afafb8a8", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "ALTERNATIVE", + "priority" : 20, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "3c4a0468-ac42-4f2c-9fc5-34520bac4645", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 20, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "8115c879-0792-4557-896c-91a529d68cf6", + "alias" : "browser", + "description" : "browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "auth-spnego", + "requirement" : "DISABLED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "identity-provider-redirector", + "requirement" : "ALTERNATIVE", + "priority" : 25, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "ALTERNATIVE", + "priority" : 30, + "flowAlias" : "forms", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "a407f9a2-8671-4fe0-b5c6-03e29e115337", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "requirement" : "ALTERNATIVE", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "client-jwt", + "requirement" : "ALTERNATIVE", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "client-secret-jwt", + "requirement" : "ALTERNATIVE", + "priority" : 30, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "client-x509", + "requirement" : "ALTERNATIVE", + "priority" : 40, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "0f232cb6-6904-4c1f-948e-e221300fa518", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "direct-grant-validate-password", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 30, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "a57ab792-c919-4f99-b662-a4e142d7c035", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "d0327c66-d41e-45d1-898c-0dae3dc3a149", + "alias" : "first broker login", + "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "REQUIRED", + "priority" : 20, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "7af247e0-a6b9-4fed-857d-d14258acd2b8", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 20, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "12c84fcd-ed90-4b34-b8be-5208945939ef", + "alias" : "http challenge", + "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "no-cookie-redirect", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "REQUIRED", + "priority" : 20, + "flowAlias" : "Authentication Options", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "c2c34d02-e57f-4341-8c05-272b5fef9f60", + "alias" : "registration", + "description" : "registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "requirement" : "REQUIRED", + "priority" : 10, + "flowAlias" : "registration form", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "ee5eb12c-033b-481b-9a91-466f3bc02581", + "alias" : "registration form", + "description" : "registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "registration-profile-action", + "requirement" : "REQUIRED", + "priority" : 40, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "registration-password-action", + "requirement" : "REQUIRED", + "priority" : 50, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "registration-recaptcha-action", + "requirement" : "DISABLED", + "priority" : 60, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + }, { + "id" : "320a7e68-e3ab-4142-a660-e2a25a434287", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "reset-credential-email", + "requirement" : "REQUIRED", + "priority" : 20, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "authenticator" : "reset-password", + "requirement" : "REQUIRED", + "priority" : 30, + "userSetupAllowed" : false, + "autheticatorFlow" : false + }, { + "requirement" : "CONDITIONAL", + "priority" : 40, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false, + "autheticatorFlow" : true + } ] + }, { + "id" : "1ad6cd70-f740-4411-bd1c-35628d7878b3", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "requirement" : "REQUIRED", + "priority" : 10, + "userSetupAllowed" : false, + "autheticatorFlow" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "9e1bf425-f911-41fe-b17e-0217b929bc22", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "7fa0e793-a298-4584-a629-f206a1f33944", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "terms_and_conditions", + "name" : "Terms and Conditions", + "providerId" : "terms_and_conditions", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "attributes" : { + "clientOfflineSessionMaxLifespan" : "0", + "clientSessionIdleTimeout" : "0", + "clientSessionMaxLifespan" : "0", + "clientOfflineSessionIdleTimeout" : "0" + }, + "keycloakVersion" : "12.0.1", + "userManagedAccessAllowed" : false +} \ No newline at end of file diff --git a/promotion/src/test/java/com/yas/promotion/controller/PromotionControllerTest.java b/promotion/src/test/java/com/yas/promotion/controller/PromotionControllerTest.java index a5e9564596..d2a628ae67 100644 --- a/promotion/src/test/java/com/yas/promotion/controller/PromotionControllerTest.java +++ b/promotion/src/test/java/com/yas/promotion/controller/PromotionControllerTest.java @@ -1,5 +1,11 @@ package com.yas.promotion.controller; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -10,10 +16,14 @@ import com.yas.promotion.model.enumeration.DiscountType; import com.yas.promotion.model.enumeration.UsageType; import com.yas.promotion.service.PromotionService; +import com.yas.promotion.viewmodel.PromotionDetailVm; +import com.yas.promotion.viewmodel.PromotionListVm; import com.yas.promotion.viewmodel.PromotionPostVm; +import com.yas.promotion.viewmodel.PromotionPutVm; import java.time.Instant; -import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.List; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -25,6 +35,8 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; @ExtendWith(SpringExtension.class) @WebMvcTest(controllers = PromotionController.class) @@ -57,11 +69,11 @@ void testCreatePromotion_whenRequestIsValid_thenReturnOk() throws Exception { .discountPercentage(10L) .usageType(UsageType.UNLIMITED) .discountType(DiscountType.PERCENTAGE) - .productIds(List.of(1L,2L,3L)) + .productIds(List.of(1L, 2L, 3L)) .isActive(true) .usageLimit(0) .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) + .endDate(Instant.now().plusSeconds(2592000)) .build(); String request = objectWriter.writeValueAsString(promotionPostVm); @@ -82,11 +94,11 @@ void testCreatePromotion_whenNameIsOverMaxLength_thenReturnBadRequest() throws E .couponCode("code") .usageType(UsageType.UNLIMITED) .discountType(DiscountType.PERCENTAGE) - .productIds(List.of(1L,2L,3L)) + .productIds(List.of(1L, 2L, 3L)) .isActive(true) .usageLimit(0) .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) + .endDate(Instant.now().plusSeconds(2592000)) .build(); String request = objectWriter.writeValueAsString(promotionPostVm); @@ -107,11 +119,11 @@ void testCreatePromotion_whenNameIsBlank_thenReturnBadRequest() throws Exception .couponCode("code") .usageType(UsageType.UNLIMITED) .discountType(DiscountType.PERCENTAGE) - .productIds(List.of(1L,2L,3L)) + .productIds(List.of(1L, 2L, 3L)) .isActive(true) .usageLimit(0) .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) + .endDate(Instant.now().plusSeconds(2592000)) .build(); String request = objectWriter.writeValueAsString(promotionPostVm); @@ -132,11 +144,11 @@ void testCreatePromotion_whenDiscountAmountIsSmallerThanZero_thenReturnBadReques .couponCode("code") .usageType(UsageType.UNLIMITED) .discountType(DiscountType.FIXED) - .productIds(List.of(1L,2L,3L)) + .productIds(List.of(1L, 2L, 3L)) .isActive(true) .usageLimit(0) .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) + .endDate(Instant.now().plusSeconds(2592000)) .build(); String request = objectWriter.writeValueAsString(promotionPostVm); @@ -157,11 +169,11 @@ void testCreatePromotion_whenDiscountPercentageIsSmallerThanZero_thenReturnBadRe .couponCode("code") .usageType(UsageType.UNLIMITED) .discountType(DiscountType.PERCENTAGE) - .productIds(List.of(1L,2L,3L)) + .productIds(List.of(1L, 2L, 3L)) .isActive(true) .usageLimit(0) .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) + .endDate(Instant.now().plusSeconds(2592000)) .build(); String request = objectWriter.writeValueAsString(promotionPostVm); @@ -182,11 +194,11 @@ void testCreatePromotion_whenDiscountPercentageIsGreaterThanHundred_thenReturnBa .couponCode("code") .usageType(UsageType.UNLIMITED) .discountType(DiscountType.PERCENTAGE) - .productIds(List.of(1L,2L,3L)) + .productIds(List.of(1L, 2L, 3L)) .isActive(true) .usageLimit(0) .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) + .endDate(Instant.now().plusSeconds(2592000)) .build(); String request = objectWriter.writeValueAsString(promotionPostVm); @@ -197,4 +209,121 @@ void testCreatePromotion_whenDiscountPercentageIsGreaterThanHundred_thenReturnBa .andExpect(status().isBadRequest()); } + @Test + void testListPromotions_whenValidRequest_thenReturnPromotionListVm() throws Exception { + + PromotionDetailVm promoDetail1 = PromotionDetailVm.builder() + .id(1L) + .name("Winter Sale") + .slug("winter-sale") + .description("Get up to 50% off on winter clothing.") + .couponCode("WINTER50") + .usageLimit(100) + .usageCount(25) + .discountType(DiscountType.PERCENTAGE) + .discountPercentage(50L) + .discountAmount(null) + .isActive(true) + .build(); + + PromotionDetailVm promoDetail2 = PromotionDetailVm.builder() + .id(2L) + .name("Summer Clearance") + .slug("summer-clearance") + .description("Flat $20 off on all summer products.") + .couponCode("SUMMER20") + .usageLimit(200) + .usageCount(50) + .discountPercentage(null) + .discountAmount(20L) + .isActive(true) + .build(); + List promotionDetails = new ArrayList<>(); + promotionDetails.add(promoDetail1); + promotionDetails.add(promoDetail2); + + PromotionListVm promotionList = PromotionListVm.builder() + .promotionDetailVmList(promotionDetails) + .pageNo(1) + .pageSize(10) + .totalElements(25) + .totalPages(3) + .build(); + + when(promotionService.getPromotions(anyInt(), anyInt(), anyString(), anyString(), + any(Instant.class), any(Instant.class))).thenReturn(promotionList); + + mockMvc.perform(MockMvcRequestBuilders.get("/backoffice/promotions") + .param("pageNo", "0") + .param("pageSize", "5") + .param("promotionName", "") + .param("couponCode", "") + .param("startDate", "1970-01-01T00:00:00Z") + .param("endDate", Instant.now().toString()) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(promotionList))); + } + + @Test + void testUpdatePromotion_whenValidRequest_thenReturnPromotionDetailVm() throws Exception { + + PromotionPutVm promotionPutVm = getPromotionPutVm(); + + PromotionDetailVm promoDetail = PromotionDetailVm.builder() + .id(1L) + .name("Holiday Discount") + .slug("holiday-discount") + .description("Enjoy a 30% discount on all items during the holiday season.") + .couponCode("HOLIDAY30") + .usageLimit(100) + .usageCount(5) + .discountType(DiscountType.PERCENTAGE) + .discountPercentage(30L) + .discountAmount(null) + .isActive(true) + .build(); + + when(promotionService.updatePromotion(promotionPutVm)).thenReturn(promoDetail); + + mockMvc.perform(MockMvcRequestBuilders.put("/backoffice/promotions") + .contentType(MediaType.APPLICATION_JSON) + .content(objectWriter.writeValueAsString(promotionPutVm))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().json(objectWriter.writeValueAsString(promoDetail))); + } + + @Test + void testDeletePromotion_whenValidRequest_deleteSuccess() throws Exception { + Long promotionId = 123L; + + doNothing().when(promotionService).deletePromotion(promotionId); + + mockMvc.perform(MockMvcRequestBuilders.delete("/backoffice/promotions/{promotionId}", promotionId) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()); + + verify(promotionService).deletePromotion(promotionId); + + } + + private static @NotNull PromotionPutVm getPromotionPutVm() { + PromotionPutVm promotionPutVm = new PromotionPutVm(); + promotionPutVm.setId(1L); + promotionPutVm.setName("abc"); + promotionPutVm.setSlug("slug"); + promotionPutVm.setCouponCode("coupon"); + promotionPutVm.setUsageType(UsageType.LIMITED); + promotionPutVm.setUsageLimit(1); + promotionPutVm.setDiscountPercentage(1L); + promotionPutVm.setDiscountType(DiscountType.PERCENTAGE); + promotionPutVm.setApplyTo(ApplyTo.PRODUCT); + promotionPutVm.setProductIds(List.of(1L)); + Instant startDate = Instant.parse("2024-12-01T00:00:00Z"); + Instant endDate = Instant.parse("2024-12-31T23:59:59Z"); + promotionPutVm.setStartDate(startDate); + promotionPutVm.setEndDate(endDate); + return promotionPutVm; + } + } diff --git a/promotion/src/test/java/com/yas/promotion/service/ProductServiceTest.java b/promotion/src/test/java/com/yas/promotion/service/ProductServiceTest.java new file mode 100644 index 0000000000..c0d2805680 --- /dev/null +++ b/promotion/src/test/java/com/yas/promotion/service/ProductServiceTest.java @@ -0,0 +1,162 @@ +package com.yas.promotion.service; + +import static com.yas.promotion.util.SecurityContextUtils.setUpSecurityContext; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.yas.promotion.config.ServiceUrlConfig; +import com.yas.promotion.viewmodel.BrandVm; +import com.yas.promotion.viewmodel.CategoryGetVm; +import com.yas.promotion.viewmodel.ProductVm; +import java.net.URI; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Objects; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +class ProductServiceTest { + + private RestClient restClient; + + private ServiceUrlConfig serviceUrlConfig; + + private ProductService productService; + + private RestClient.ResponseSpec responseSpec; + + private static final String PRODUCT_URL = "http://api.yas.local/product"; + + @BeforeEach + void setUp() { + restClient = mock(RestClient.class); + serviceUrlConfig = mock(ServiceUrlConfig.class); + productService = new ProductService(restClient, serviceUrlConfig); + responseSpec = Mockito.mock(RestClient.ResponseSpec.class); + setUpSecurityContext("test"); + when(serviceUrlConfig.product()).thenReturn(PRODUCT_URL); + } + + @Test + void testGetProductByIds_ifNormalCase_returnProductVms() { + + List ids = List.of(1L); + + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.product()) + .path("/backoffice/products/by-ids") + .queryParams(createIdParams(ids)) + .build() + .toUri(); + + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.get()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + + ProductVm product = new ProductVm( + 1L, + "Example Product", + "example-product", + true, + true, + false, + true, + ZonedDateTime.now(), + 2L + ); + + when(responseSpec.toEntity(new ParameterizedTypeReference>() {})) + .thenReturn(ResponseEntity.ok(List.of(product))); + + List result = productService.getProductByIds(ids); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().id()).isEqualTo(1); + + } + + @Test + void testGetCategoryByIds_ifNormalCase_returnCategoryGetVms() { + + List ids = List.of(2L); + + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.product()) + .path("/backoffice/categories/by-ids") + .queryParams(createIdParams(ids)) + .build() + .toUri(); + + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.get()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + + CategoryGetVm category = new CategoryGetVm( + 2L, + "Example Category", + "example-category", + 0L + ); + + when(responseSpec.toEntity(new ParameterizedTypeReference>() {})) + .thenReturn(ResponseEntity.ok(List.of(category))); + + List result = productService.getCategoryByIds(ids); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().id()).isEqualTo(2); + } + + @Test + void testGetBrandByIds_ifNormalCase_returnBrandVms() { + + List ids = List.of(4L); + + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.product()) + .path("/backoffice/brands/by-ids") + .queryParams(createIdParams(ids)) + .build() + .toUri(); + + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.get()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + + BrandVm brand = new BrandVm( + 3L, + "Example Brand", + "example-brand", + true + ); + + when(responseSpec.toEntity(new ParameterizedTypeReference>() {})) + .thenReturn(ResponseEntity.ok(List.of(brand))); + + List result = productService.getBrandByIds(ids); + + assertThat(result).hasSize(1); + assertThat(result.getFirst().id()).isEqualTo(3); + } + + private MultiValueMap createIdParams(List ids) { + MultiValueMap params = new LinkedMultiValueMap<>(); + ids.stream().map(Objects::toString).forEach(id -> params.add("ids", id)); + return params; + } +} \ No newline at end of file diff --git a/promotion/src/test/java/com/yas/promotion/service/PromotionServiceTest.java b/promotion/src/test/java/com/yas/promotion/service/PromotionServiceTest.java deleted file mode 100644 index 75578389c2..0000000000 --- a/promotion/src/test/java/com/yas/promotion/service/PromotionServiceTest.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.yas.promotion.service; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import com.yas.promotion.PromotionApplication; -import com.yas.promotion.exception.BadRequestException; -import com.yas.promotion.exception.DuplicatedException; -import com.yas.promotion.model.Promotion; -import com.yas.promotion.model.PromotionApply; -import com.yas.promotion.model.enumeration.ApplyTo; -import com.yas.promotion.model.enumeration.DiscountType; -import com.yas.promotion.repository.PromotionRepository; -import com.yas.promotion.utils.Constants; -import com.yas.promotion.viewmodel.PromotionDetailVm; -import com.yas.promotion.viewmodel.PromotionListVm; -import com.yas.promotion.viewmodel.PromotionPostVm; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.List; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; - -@SpringBootTest(classes = PromotionApplication.class) -class PromotionServiceTest { - @Autowired - private PromotionRepository promotionRepository; - @MockBean - private ProductService productService; - @Autowired - private PromotionService promotionService; - - private Promotion promotion1; - private Promotion wrongRangeDatePromotion; - private PromotionPostVm promotionPostVm; - - @BeforeEach - void setUp() { - promotion1 = Promotion.builder() - .name("Promotion 1") - .slug("promotion-1") - .description("Description 1") - .couponCode("code1") - .discountAmount(100L) - .discountPercentage(10L) - .isActive(true) - .startDate(Instant.now()) - .endDate(Instant.now().plus(30, ChronoUnit.DAYS)) - .applyTo(ApplyTo.BRAND) - .promotionApplies( - List.of(PromotionApply.builder().brandId(1L).build())) - .build(); - promotion1 = promotionRepository.save(promotion1); - - Promotion promotion2 = Promotion.builder() - .name("Promotion 2") - .slug("promotion-2") - .description("Description 2") - .couponCode("code2") - .discountAmount(200L) - .discountPercentage(20L) - .isActive(false) - .startDate(Instant.now().plus(30, ChronoUnit.DAYS)) - .endDate(Instant.now().plus(60, ChronoUnit.DAYS)) - .applyTo(ApplyTo.PRODUCT) - .promotionApplies( - List.of(PromotionApply.builder().productId(1L).build())) - .build(); - promotionRepository.save(promotion2); - - wrongRangeDatePromotion = Promotion.builder() - .name("Wrong date") - .slug("wrong-date") - .description("Promotion with invalid date range") - .couponCode("codeWrong") - .discountAmount(200L) - .discountPercentage(20L) - .applyTo(ApplyTo.PRODUCT) - .isActive(false) - .startDate(Instant.now().plus(30, ChronoUnit.DAYS)) - .endDate(Instant.now().plus(60, ChronoUnit.DAYS)) - .build(); - wrongRangeDatePromotion = promotionRepository.save(wrongRangeDatePromotion); - } - - @AfterEach - void tearDown() { - promotionRepository.deleteAll(); - } - - @Test - void createPromotion_ThenSuccess() { - promotionPostVm = PromotionPostVm.builder() - .name("Promotion 3") - .slug("promotion-3") - .description("Description 3") - .couponCode("code3") - .discountType(DiscountType.FIXED) - .discountAmount(300L) - .discountPercentage(30L) - .isActive(true) - .startDate(Instant.now().plus(60, ChronoUnit.DAYS)) - .endDate(Instant.now().plus(90, ChronoUnit.DAYS)) - .applyTo(ApplyTo.PRODUCT) - .productIds(List.of(1L, 2L, 3L)) - .build(); - - PromotionDetailVm result = promotionService.createPromotion(promotionPostVm); - assertEquals(promotionPostVm.getSlug(), result.slug()); - assertEquals(promotionPostVm.getName(), result.name()); - assertEquals(true, result.isActive()); - } - - @Test - void createPromotion_WhenExistedSlug_ThenDuplicatedExceptionThrown() { - promotionPostVm = PromotionPostVm.builder() - .slug(promotion1.getSlug()) - .applyTo(ApplyTo.PRODUCT) - .name("12345") - .couponCode("cp-12345") - .productIds(List.of(1L, 2L, 3L)) - .discountType(DiscountType.FIXED) - .discountAmount(300L) - .discountPercentage(30L) - .build(); - assertThrows(DuplicatedException.class, () -> promotionService.createPromotion(promotionPostVm), - String.format(Constants.ErrorCode.SLUG_ALREADY_EXITED, promotionPostVm.getSlug())); - } - - @Test - void createPromotion_WhenEndDateBeforeStartDate_ThenDateRangeExceptionThrown() { - promotionPostVm = PromotionPostVm.builder() - .applyTo(ApplyTo.PRODUCT) - .name("12345") - .couponCode("cp-12345") - .productIds(List.of(1L, 2L, 3L)) - .endDate(Instant.now().minus(2, ChronoUnit.DAYS)) - .startDate(Instant.now()) - .build(); - - BadRequestException exception = assertThrows(BadRequestException.class, () -> - promotionService.createPromotion(promotionPostVm) - ); - assertEquals(String.format(Constants.ErrorCode.DATE_RANGE_INVALID), exception.getMessage()); - } - - @Test - void getPromotionList_ThenSuccess() { - PromotionListVm result = promotionService.getPromotions(0, 5, - "Promotion", "code", - Instant.now().minus(120, ChronoUnit.DAYS), Instant.now().plus(120, ChronoUnit.DAYS)); - assertEquals(2, result.promotionDetailVmList().size()); - PromotionDetailVm promotionDetailVm = result.promotionDetailVmList().getFirst(); - assertEquals("promotion-1", promotionDetailVm.slug()); - } -} diff --git a/promotion/src/test/java/com/yas/promotion/util/SecurityContextUtils.java b/promotion/src/test/java/com/yas/promotion/util/SecurityContextUtils.java new file mode 100644 index 0000000000..89772def98 --- /dev/null +++ b/promotion/src/test/java/com/yas/promotion/util/SecurityContextUtils.java @@ -0,0 +1,27 @@ +package com.yas.promotion.util; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; + +public class SecurityContextUtils { + + private SecurityContextUtils() { + } + + public static void setUpSecurityContext(String userName) { + Authentication auth = mock(Authentication.class); + when(auth.getName()).thenReturn(userName); + Jwt jwt = mock(Jwt.class); + when(auth.getPrincipal()).thenReturn(jwt); + when(jwt.getTokenValue()).thenReturn("token"); + SecurityContext securityContext = mock(SecurityContext.class); + when(securityContext.getAuthentication()).thenReturn(auth); + SecurityContextHolder.setContext(securityContext); + } + +} diff --git a/promotion/src/test/java/com/yas/promotion/validation/PromotionValidatorTest.java b/promotion/src/test/java/com/yas/promotion/validation/PromotionValidatorTest.java new file mode 100644 index 0000000000..fb1aaf4ed3 --- /dev/null +++ b/promotion/src/test/java/com/yas/promotion/validation/PromotionValidatorTest.java @@ -0,0 +1,155 @@ +package com.yas.promotion.validation; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +import com.yas.promotion.model.enumeration.ApplyTo; +import com.yas.promotion.model.enumeration.DiscountType; +import com.yas.promotion.model.enumeration.UsageType; +import com.yas.promotion.viewmodel.PromotionDto; +import jakarta.validation.ConstraintValidatorContext; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +class PromotionValidatorTest { + + private final PromotionValidator validator = new PromotionValidator(); + + @Test + void testIsValid_whenAppleToProduct_isValidTrue() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.LIMITED); + dto.setUsageLimit(10); + dto.setDiscountType(DiscountType.FIXED); + dto.setDiscountAmount(5L); + dto.setApplyTo(ApplyTo.PRODUCT); + dto.setProductIds(Collections.singletonList(1L)); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertTrue(isValid); + } + + @Test + void testIsValid_whenAppleToCategory_isValidTrue() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.LIMITED); + dto.setUsageLimit(10); + dto.setDiscountType(DiscountType.FIXED); + dto.setDiscountAmount(5L); + dto.setApplyTo(ApplyTo.CATEGORY); + dto.setCategoryIds(Collections.singletonList(1L)); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertTrue(isValid); + } + + @Test + void testIsValid_whenAppleToBrand_isValidTrue() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.LIMITED); + dto.setUsageLimit(10); + dto.setDiscountType(DiscountType.FIXED); + dto.setDiscountAmount(5L); + dto.setApplyTo(ApplyTo.BRAND); + dto.setBrandIds(Collections.singletonList(1L)); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertTrue(isValid); + } + + @Test + void testIsValid_whenUsageLimitIs0_isValidFalse() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.LIMITED); + dto.setUsageLimit(0); + dto.setDiscountType(DiscountType.PERCENTAGE); + dto.setDiscountPercentage(1L); + dto.setDiscountAmount(5L); + dto.setApplyTo(ApplyTo.CATEGORY); + dto.setCategoryIds(Collections.singletonList(1L)); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertFalse(isValid); + } + + @Test + void testIsValid_whenDiscountTypeIsFixedAndDiscountAmountIs0_isValidFalse() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.UNLIMITED); + dto.setUsageLimit(10); + dto.setDiscountType(DiscountType.FIXED); + dto.setDiscountAmount(0L); + dto.setApplyTo(ApplyTo.BRAND); + dto.setBrandIds(Collections.singletonList(1L)); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertFalse(isValid); + } + + @Test + void testIsValid_whenApplyToIsProductAndProductIdsIdEmpty_isValidFalse() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.UNLIMITED); + dto.setUsageLimit(10); + dto.setDiscountType(DiscountType.PERCENTAGE); + dto.setDiscountPercentage(10L); + dto.setApplyTo(ApplyTo.PRODUCT); + dto.setProductIds(Collections.emptyList()); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertFalse(isValid); + } + + @Test + void testIsValid_whenApplyToIsBrandAndBrandIdsIdEmpty_isValidFalse() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.UNLIMITED); + dto.setUsageLimit(9); + dto.setDiscountType(DiscountType.PERCENTAGE); + dto.setDiscountPercentage(10L); + dto.setApplyTo(ApplyTo.BRAND); + dto.setBrandIds(Collections.emptyList()); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertFalse(isValid); + } + + @Test + void testIsValid_whenApplyToIsCategoryAndCategoryIdsIdEmpty_isValidFalse() { + + PromotionDto dto = new PromotionDto(); + dto.setUsageType(UsageType.UNLIMITED); + dto.setUsageLimit(11); + dto.setDiscountType(DiscountType.PERCENTAGE); + dto.setDiscountPercentage(10L); + dto.setApplyTo(ApplyTo.CATEGORY); + dto.setCategoryIds(Collections.emptyList()); + + ConstraintValidatorContext context = mock(ConstraintValidatorContext.class); + boolean isValid = validator.isValid(dto, context); + + assertFalse(isValid); + } +} diff --git a/rating/src/test/java/com/yas/rating/service/OrderServiceTest.java b/rating/src/test/java/com/yas/rating/service/OrderServiceTest.java new file mode 100644 index 0000000000..e09c5e0f38 --- /dev/null +++ b/rating/src/test/java/com/yas/rating/service/OrderServiceTest.java @@ -0,0 +1,83 @@ +package com.yas.rating.service; + +import static com.yas.rating.util.SecurityContextUtils.setUpSecurityContext; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.yas.rating.config.ServiceUrlConfig; +import com.yas.rating.viewmodel.OrderExistsByProductAndUserGetVm; +import java.net.URI; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.client.RestClient; +import org.springframework.web.util.UriComponentsBuilder; + +class OrderServiceTest { + + private RestClient restClient; + + private ServiceUrlConfig serviceUrlConfig; + + private OrderService orderService; + + private RestClient.ResponseSpec responseSpec; + + private static final String ORDER_URL = "http://api.yas.local/order"; + + @BeforeEach + void setUp() { + restClient = mock(RestClient.class); + serviceUrlConfig = mock(ServiceUrlConfig.class); + orderService = new OrderService(restClient, serviceUrlConfig); + responseSpec = Mockito.mock(RestClient.ResponseSpec.class); + } + + @AfterEach + void tearDown() { + SecurityContextHolder.clearContext(); + } + + @Test + void testCheckOrderExistsByProductAndUserWithStatus_whenNormalCase_returnOrderExistsByProductAndUserGetVm() { + + when(serviceUrlConfig.order()).thenReturn(ORDER_URL); + URI url = UriComponentsBuilder + .fromHttpUrl(serviceUrlConfig.order()) + .path("/storefront/orders/completed") + .queryParam("productId", "1") + .buildAndExpand() + .toUri(); + + setUpSecurityContext("test"); + RestClient.RequestHeadersUriSpec requestHeadersUriSpec = Mockito.mock(RestClient.RequestHeadersUriSpec.class); + when(restClient.get()).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.headers(any())).thenReturn(requestHeadersUriSpec); + when(requestHeadersUriSpec.retrieve()).thenReturn(responseSpec); + + OrderExistsByProductAndUserGetVm orderExistsByProductAndUserGetVm + = new OrderExistsByProductAndUserGetVm(true); + when(responseSpec.body(OrderExistsByProductAndUserGetVm.class)) + .thenReturn(orderExistsByProductAndUserGetVm); + + OrderExistsByProductAndUserGetVm result = orderService.checkOrderExistsByProductAndUserWithStatus(1L); + + assertThat(result.isPresent()).isTrue(); + + } + + @Test + void testHandleFallback_whenNewOrderExistsByProductAndUserGetVm_returnOrderExistsByProductAndUserGetVm() + throws Throwable { + + OrderExistsByProductAndUserGetVm result = orderService.handleFallback(mock(Throwable.class)); + assertThat(result.isPresent()).isFalse(); + + } + +} \ No newline at end of file diff --git a/rating/src/test/java/com/yas/rating/util/SecurityContextUtils.java b/rating/src/test/java/com/yas/rating/util/SecurityContextUtils.java new file mode 100644 index 0000000000..aa940ac78a --- /dev/null +++ b/rating/src/test/java/com/yas/rating/util/SecurityContextUtils.java @@ -0,0 +1,27 @@ +package com.yas.rating.util; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; + +public class SecurityContextUtils { + + private SecurityContextUtils() { + } + + public static void setUpSecurityContext(String userName) { + Authentication auth = mock(Authentication.class); + when(auth.getName()).thenReturn(userName); + Jwt jwt = mock(Jwt.class); + when(auth.getPrincipal()).thenReturn(jwt); + when(jwt.getTokenValue()).thenReturn("token"); + SecurityContext securityContext = mock(SecurityContext.class); + when(securityContext.getAuthentication()).thenReturn(auth); + SecurityContextHolder.setContext(securityContext); + } + +}