diff --git a/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/BankAccountServiceTest.java b/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/BankAccountServiceTest.java index b88f625a2..14077bfac 100644 --- a/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/BankAccountServiceTest.java +++ b/clearing-parent/account-service/src/test/java/ru/spcex/clearing/account/service/BankAccountServiceTest.java @@ -37,7 +37,7 @@ import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFields @ContextConfiguration(classes = { HazelcastServiceTestConfiguration.class}) public class BankAccountServiceTest { - public static final Matcher BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator("id"); + public static final Matcher BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator(); private static final int PARTITION = 0; private static final String TOPIC_ACCOUNT_NEW = Consts.DESTINATION_BANK_ACCOUNT_NEW; private static final String TOPIC_ACCOUNT_UPDATE = Consts.DESTINATION_BANK_ACCOUNT_UPDATE; diff --git a/clearing-parent/backend-api/pom.xml b/clearing-parent/backend-api/pom.xml index d0385f3f5..ad0714978 100644 --- a/clearing-parent/backend-api/pom.xml +++ b/clearing-parent/backend-api/pom.xml @@ -61,6 +61,27 @@ ru.spcex.platform platform-enum + + + org.springframework + spring-test + test + + + org.skyscreamer + jsonassert + test + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + @@ -156,6 +177,24 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + 2.21.0 + + + org.junit.platform + junit-platform-surefire-provider + 1.2.0-M1 + + + org.junit.jupiter + junit-jupiter-engine + 5.2.0-M1 + + + \ No newline at end of file diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/AbstractControllerTest.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/AbstractControllerTest.java new file mode 100644 index 000000000..4b941266d --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/AbstractControllerTest.java @@ -0,0 +1,54 @@ +package ru.spcex.clearing.backendapi.controller.queue; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.filter.CharacterEncodingFilter; +import ru.spcex.clearing.backendapi.config.WebConfig; +import ru.spcex.clearing.backendapi.controller.queue.company.DeleteCompanyController; +import ru.spcex.clearing.backendapi.controller.queue.config.*; + +import javax.annotation.PostConstruct; +import java.util.concurrent.atomic.AtomicLong; + + +@SpringJUnitWebConfig(classes = { + WebConfig.class, + IOperator.class, + StateLoaderImplConfig.class, + DeleteCompanyController.class, + BankAccountControllerConfig.class, + KafkaConfig.class, + HazelcastServiceTestConfiguration.class, + Jackson2HttpConverterConfig.class}) +public abstract class AbstractControllerTest { + protected static final AtomicLong currentId = new AtomicLong(); + private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter(); + + static { + CHARACTER_ENCODING_FILTER.setEncoding("UTF-8"); + CHARACTER_ENCODING_FILTER.setForceEncoding(true); + } + + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext webApplicationContext; + + @PostConstruct + private void postConstruct() { + mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .addFilter(CHARACTER_ENCODING_FILTER) +// .apply(springSecurity()) + .build(); + } + + protected ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception { + return mockMvc.perform(builder); + } +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/account/BankAccountControllerTest.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/account/BankAccountControllerTest.java new file mode 100644 index 000000000..e0705f548 --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/account/BankAccountControllerTest.java @@ -0,0 +1,245 @@ +package ru.spcex.clearing.backendapi.controller.queue.account; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.NestedExceptionUtils; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.filter.CharacterEncodingFilter; +import ru.spcex.clearing.backendapi.config.WebConfig; +import ru.spcex.clearing.backendapi.controller.queue.config.*; +import ru.spcex.clearing.backendapi.controller.queue.utils.MatcherFactory; +import ru.spcex.clearing.backendapi.controller.request.cud.account.BankAccountNewAction; +import ru.spcex.clearing.backendapi.controller.request.cud.account.BankAccountUpdateAction; +import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse; +import ru.spcex.clearing.backendapi.controller.response.cud.QueueSuccessResponse; +import ru.spcex.clearing.backendapi.domain.actions.IAction; +import ru.spcex.clearing.backendapi.errors.ActionValidationException; +import ru.spcex.clearing.platform.messaging.domain.ActionType; +import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountNewRequest; + +import javax.annotation.PostConstruct; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.spcex.clearing.backendapi.controller.queue.utils.JsonUtil.writeValue; + +@SpringJUnitWebConfig(classes = { + WebConfig.class, + IOperator.class, + BankAccountControllerConfig.class, + KafkaConfig.class, + HazelcastServiceTestConfiguration.class, + Jackson2HttpConverterConfig.class}) +class BankAccountControllerTest { + + public static final MatcherFactory.Matcher CUD_RESPONSE_MATCHER = MatcherFactory.usingIgnoringFieldsComparator(CudResponse.class); + private static final String REST_URL = "/securities/bank-accounts/"; + private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter(); + private static final AtomicLong currentId = new AtomicLong(); + + static { + CHARACTER_ENCODING_FILTER.setEncoding("UTF-8"); + CHARACTER_ENCODING_FILTER.setForceEncoding(true); + } + + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext webApplicationContext; + + @PostConstruct + private void postConstruct() { + mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .addFilter(CHARACTER_ENCODING_FILTER) +// .apply(springSecurity()) + .build(); + } + + /** + * {@link BankAccountController#add(BankAccountNewAction)}
+ * Тест проверяет получение сущности {@link BankAccountNewAction} по REST API и отправку в Apache Kafka.
+ * Входной запрос {@link BankAccountNewRequest}:
+ * {@link BankAccountNewRequest#bankIdentificationCode} - 044525776
+ * {@link BankAccountNewRequest#bankName} - Beta Money Bank
+ * {@link BankAccountNewRequest#correspondentAccount} - 30101111111111111776
+ * {@link BankAccountNewRequest#correspondentAccountName} - correspondent
+ * {@link BankAccountNewRequest#currency} - RUB
+ * {@link BankAccountNewRequest#destination} - destination
+ * {@link BankAccountNewRequest#taxpayerIdentificationNumber} - 3664011397
+ * {@link BankAccountNewRequest#taxRegistrationReasonCode} - 01
+ * {@link BankAccountNewRequest#account} - 11111222223333344444
+ */ + @Test + void add() throws Exception { + //ARRANGE + BankAccountNewAction bankAccountNewAction = getBankAccountNewAction( + "044525776", + "Beta Money Bank", + "30101111111111111776", + "correspondent", + "RUB", + "destination", + "3664011397", + "01", + "11111222223333344444"); + + CudResponse extended = new CudResponse(); + extended.setCode(0L); + extended.setMessage("success"); + extended.setPayload(new QueueSuccessResponse(ActionType.NEW, currentId.getAndIncrement())); + //ACT + mockMvc.perform(MockMvcRequestBuilders.post(REST_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(writeValue(bankAccountNewAction))) + .andDo(print())//output to the log request and response +// ASSERT + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(content().json(writeValue(extended))); + } + + /** + * {@link BankAccountController#add(BankAccountNewAction)}
+ * Тест проверяет работу валидации сущности {@link BankAccountNewAction} принятой по REST API для отправку в Apache Kafka.
+ * Входной запрос {@link BankAccountNewRequest}:
+ * {@link BankAccountNewRequest#bankIdentificationCode} - 044525776 или ""
+ * {@link BankAccountNewRequest#bankName} - Beta Money Bank или ""
+ * {@link BankAccountNewRequest#correspondentAccount} - 30101111111111111776 или ""
+ * {@link BankAccountNewRequest#correspondentAccountName} - correspondent или ""
+ * {@link BankAccountNewRequest#currency} - RUB или ""
+ * {@link BankAccountNewRequest#destination} - destinatio или ""n
+ * {@link BankAccountNewRequest#taxpayerIdentificationNumber} - 3664011397 или ""
+ * {@link BankAccountNewRequest#taxRegistrationReasonCode} - 01 или ""
+ * {@link BankAccountNewRequest#account} - 11111222223333344444 или ""
+ */ + @Test + void addWithException() { + assertThrowsFor(getBankAccountNewAction("", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "", "correspondent", "RUB", "destination", "3664011397", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "", "RUB", "destination", "3664011397", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "", "destination", "3664011397", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "", "3664011397", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "", "01", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "", "11111222223333344444")); + assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "01", "")); + } + + /** + * {@link BankAccountController#update(Long, BankAccountUpdateAction)}
+ * Тест проверяет получение сущности {@link BankAccountUpdateAction} по REST API и отправку в Apache Kafka.
+ * Входной запрос {@link BankAccountUpdateAction}:
+ * {@link BankAccountUpdateAction#bankIdentificationCode} - 044525776
+ * {@link BankAccountUpdateAction#bankName} - Beta Money Bank
+ * {@link BankAccountUpdateAction#correspondentAccount} - 30101111111111111776
+ * {@link BankAccountUpdateAction#correspondentAccountName} - correspondent
+ * {@link BankAccountUpdateAction#currency} - RUB
+ * {@link BankAccountUpdateAction#destination} - destination
+ * {@link BankAccountUpdateAction#taxpayerIdentificationNumber} - 3664011397
+ * {@link BankAccountUpdateAction#taxRegistrationReasonCode} - 01
+ * {@link BankAccountUpdateAction#account} - 11111222223333344444
+ */ + @Test + void update() throws Exception { + //ARRANGE + BankAccountUpdateAction bankAccountNewAction = getBankAccountUpdateAction( + "044525776", + "Beta Money Bank", + "30101111111111111776", + "correspondent", + "RUB", + "destination", + "3664011397", + "01", + "11111222223333344444"); + + CudResponse extended = new CudResponse(); + extended.setCode(0L); + extended.setMessage("success"); + extended.setPayload(new QueueSuccessResponse(ActionType.UPDATE, currentId.getAndIncrement())); + //ACT + mockMvc.perform(MockMvcRequestBuilders.put(REST_URL + "0") + .contentType(MediaType.APPLICATION_JSON) + .content(writeValue(bankAccountNewAction))) + .andDo(print())//output to the log request and response +// ASSERT + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(content().json(writeValue(extended))); + } + + + /** + * {@link BankAccountController#delete(Long)}
+ * Тест проверяет получение id сущности {@link Long} по REST API и отправку в Apache Kafka.
+ * Входной запрос {@link Long}: - 0L
+ */ + @Test + void delete() throws Exception { + //ARRANGE + CudResponse extended = new CudResponse(); + extended.setCode(0L); + extended.setMessage("success"); + extended.setPayload(new QueueSuccessResponse(ActionType.DELETE, currentId.getAndIncrement())); + //ACT + mockMvc.perform(MockMvcRequestBuilders.delete(REST_URL + "0") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print())//output to the log request and response +// ASSERT + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(content().json(writeValue(extended))); + } + + private void assertThrowsFor(IAction iAction) { + assertThrows(ActionValidationException.class, () -> { + try { + mockMvc.perform(MockMvcRequestBuilders.post(REST_URL).contentType(MediaType.APPLICATION_JSON).content(writeValue(iAction))); + } catch (Exception e) { + Throwable rootCause = NestedExceptionUtils.getRootCause(e); + throw rootCause != null ? rootCause : e; + } + }); + } + + private BankAccountNewAction getBankAccountNewAction(String BankIdentificationCode, String BankName, String CorrespondentAccount, String CorrespondentAccountName, + String Currency, String Destination, String TaxpayerIdentificationNumber, String TaxRegistrationReasonCode, + String Account) { + BankAccountNewAction bankAccountNewAction = new BankAccountNewAction(); + bankAccountNewAction.setBankIdentificationCode(BankIdentificationCode); + bankAccountNewAction.setBankName(BankName); + bankAccountNewAction.setCorrespondentAccount(CorrespondentAccount); + bankAccountNewAction.setCorrespondentAccountName(CorrespondentAccountName); + bankAccountNewAction.setCurrency(Currency); + bankAccountNewAction.setDestination(Destination); + bankAccountNewAction.setTaxpayerIdentificationNumber(TaxpayerIdentificationNumber); + bankAccountNewAction.setTaxRegistrationReasonCode(TaxRegistrationReasonCode); + bankAccountNewAction.setAccount(Account); + return bankAccountNewAction; + } + + private BankAccountUpdateAction getBankAccountUpdateAction(String BankIdentificationCode, String BankName, String CorrespondentAccount, String CorrespondentAccountName, + String Currency, String Destination, String TaxpayerIdentificationNumber, String TaxRegistrationReasonCode, + String Account) { + BankAccountUpdateAction bankAccountUpdateAction = new BankAccountUpdateAction(); + bankAccountUpdateAction.setBankIdentificationCode(BankIdentificationCode); + bankAccountUpdateAction.setBankName(BankName); + bankAccountUpdateAction.setCorrespondentAccount(CorrespondentAccount); + bankAccountUpdateAction.setCorrespondentAccountName(CorrespondentAccountName); + bankAccountUpdateAction.setCurrency(Currency); + bankAccountUpdateAction.setDestination(Destination); + bankAccountUpdateAction.setTaxpayerIdentificationNumber(TaxpayerIdentificationNumber); + bankAccountUpdateAction.setTaxRegistrationReasonCode(TaxRegistrationReasonCode); + bankAccountUpdateAction.setAccount(Account); + return bankAccountUpdateAction; + } +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/company/DeleteCompanyControllerTest.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/company/DeleteCompanyControllerTest.java new file mode 100644 index 000000000..1673abc9d --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/company/DeleteCompanyControllerTest.java @@ -0,0 +1,40 @@ +package ru.spcex.clearing.backendapi.controller.queue.company; + +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import ru.spcex.clearing.backendapi.controller.queue.AbstractControllerTest; +import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse; +import ru.spcex.clearing.backendapi.controller.response.cud.QueueSuccessResponse; +import ru.spcex.clearing.platform.messaging.domain.ActionType; + +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static ru.spcex.clearing.backendapi.controller.queue.utils.JsonUtil.writeValue; + +class DeleteCompanyControllerTest extends AbstractControllerTest { + private static final String REST_URL = "/companies/"; + + /** + * {@link DeleteCompanyController#delete(Long)}
+ * Тест проверяет получение id сущности {@link Long} по REST API и отправку в Apache Kafka.
+ * Входной запрос {@link Long}: - 0L
+ */ + @Test + void delete() throws Exception { + //ARRANGE + CudResponse extended = new CudResponse(); + extended.setCode(0L); + extended.setMessage("success"); + extended.setPayload(new QueueSuccessResponse(ActionType.DELETE, currentId.getAndIncrement())); + //ACT + perform(MockMvcRequestBuilders.delete(REST_URL + "0") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(print())//output to the log request and response +// ASSERT + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(content().json(writeValue(extended))); + } +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/BankAccountControllerConfig.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/BankAccountControllerConfig.java new file mode 100644 index 000000000..02d79864d --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/BankAccountControllerConfig.java @@ -0,0 +1,28 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.backendapi.controller.queue.account.BankAccountController; +import ru.spcex.clearing.backendapi.service.IOperator; +import ru.spcex.clearing.backendapi.service.impl.StateLoaderImpl; + + +@Configuration +public class BankAccountControllerConfig { + + @Autowired + + @Qualifier("iOperator") + private IOperator operator; + + @Autowired + @Qualifier("stateLoaderImpl") + private StateLoaderImpl stateLoader; + + @Bean + public BankAccountController createBankAccountController() { + return new BankAccountController(operator, stateLoader); + } +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/DeleteCompanyControllerConfig.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/DeleteCompanyControllerConfig.java new file mode 100644 index 000000000..5a5aab4c0 --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/DeleteCompanyControllerConfig.java @@ -0,0 +1,25 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.backendapi.controller.queue.company.DeleteCompanyController; +import ru.spcex.clearing.backendapi.service.IOperator; +import ru.spcex.clearing.backendapi.service.impl.StateLoaderImpl; + +@Configuration +public class DeleteCompanyControllerConfig { + @Autowired + @Qualifier("iOperator") + private IOperator operator; + + @Autowired + @Qualifier("stateLoaderImpl") + private StateLoaderImpl stateLoader; + + @Bean + public DeleteCompanyController createDeleteCompanyController() { + return new DeleteCompanyController(operator, stateLoader); + } +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/HazelcastServiceTestConfiguration.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/HazelcastServiceTestConfiguration.java new file mode 100644 index 000000000..04e64990d --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/HazelcastServiceTestConfiguration.java @@ -0,0 +1,68 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import com.hazelcast.config.*; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper; + +import java.util.List; +import java.util.Random; + +@Configuration +public class HazelcastServiceTestConfiguration { + private HazelcastInstance hazelcastInstance; + + private static ThreadPoolTaskExecutor createThreadPoolTaskExecutor(int maxPoolSz, boolean waitForCompletion) { + ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); + if (maxPoolSz > 2) { + pool.setKeepAliveSeconds(60); + pool.setAllowCoreThreadTimeOut(true); + } + pool.setCorePoolSize(maxPoolSz); + pool.setWaitForTasksToCompleteOnShutdown(waitForCompletion); + return pool; + } + + @Bean(name = "hazelcastServiceTest") + public HazelcastService hazelcastService(@Qualifier("taskExecutorHazelcastClientInitializer") ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer, @Qualifier("taskExecutorIdGeneratorAwaiter") ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter, HazelcastClientParams params) { + Config cfg = new Config(); + cfg.setInstanceName("localhost"); + + NetworkConfig networkConfig = new NetworkConfig(); + JoinConfig joinConfig = new JoinConfig(); + joinConfig.setMulticastConfig(new MulticastConfig().setEnabled(false)); + joinConfig.setTcpIpConfig(new TcpIpConfig().setEnabled(true).setMembers(List.of("127.0.0.1"))); + networkConfig.setJoin(joinConfig); + cfg.setNetworkConfig(networkConfig); + hazelcastInstance = Hazelcast.newHazelcastInstance(cfg); + HazelcastHelper.otcSystem_setStorageState(true, hazelcastInstance); + return new HazelcastService(taskExecutorHazelcastClientInitializer, taskExecutorIdGeneratorAwaiter, params); + } + + @Bean(name = "taskExecutorHazelcastClientInitializer") + public ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer() { + return createThreadPoolTaskExecutor(1, true); + } + + @Bean(name = "taskExecutorIdGeneratorAwaiter") + public ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter() { + return createThreadPoolTaskExecutor(1, false); + } + + @Bean(name = "hazelcastClientParams") + public HazelcastClientParams getHazelcastClientParams() { + HazelcastClientParams params = new HazelcastClientParams(); + params.setLogin("dev"); + params.setPassword("dev-pass"); + params.setClusterMembers("127.0.0.1"); + params.setInstanceName("hzTestClient" + new Random().nextInt()); + params.setNearCacheConfig(new NearCacheConfig()); + return params; + } +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/IOperator.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/IOperator.java new file mode 100644 index 000000000..065785269 --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/IOperator.java @@ -0,0 +1,24 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import org.apache.kafka.clients.producer.Producer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.backendapi.service.impl.OperatorImpl; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; + +@Configuration +public class IOperator { + + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + @Autowired + @Bean + public OperatorImpl createIOperator(Producer kafka) { + return new OperatorImpl(kafka, hazelcastServiceTest); + } + +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/Jackson2HttpConverterConfig.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/Jackson2HttpConverterConfig.java new file mode 100644 index 000000000..a1f8c5bea --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/Jackson2HttpConverterConfig.java @@ -0,0 +1,41 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +@Configuration +public class Jackson2HttpConverterConfig { + @Bean("customJsonHttpConverter") + public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { + return new MappingJackson2HttpMessageConverter(JacksonObjectMapper.getMapper()); + } + + public static class JacksonObjectMapper extends ObjectMapper { + private static final ObjectMapper MAPPER = new JacksonObjectMapper(); + + private JacksonObjectMapper() { + //настройки Ильи + configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true); + + //настройки какие были на курсе пока не нужны.. +// модуль для корректной сериализации LocalDateTime в поля JSON - JavaTimeModule модуль библиотеки jackson-datatype-jsr310 +// registerModule(new JavaTimeModule()); +// configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + +// запрещаем доступ ко всем полям и методам класса и потом разрешаем доступ только к полям, нужны чтобы не было лишних полей из-за методов как: public ActionType getActionType() у BankAccountNewAction + setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); + setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); +// не сериализуем null-поля +// setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + + public static ObjectMapper getMapper() { + return MAPPER; + } + } +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/KafkaConfig.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/KafkaConfig.java new file mode 100644 index 000000000..e8c020252 --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/KafkaConfig.java @@ -0,0 +1,18 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.platform.messaging.serialization.JsonSerializer; + +@Configuration +public class KafkaConfig { + + @Bean + public Producer createProducer() { + return new MockProducer<>(true, new StringSerializer(), new JsonSerializer()); + } + +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/StateLoaderImplConfig.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/StateLoaderImplConfig.java new file mode 100644 index 000000000..b566a6bbc --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/config/StateLoaderImplConfig.java @@ -0,0 +1,22 @@ +package ru.spcex.clearing.backendapi.controller.queue.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import ru.spcex.clearing.backendapi.service.impl.StateLoaderImpl; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; + +@Configuration +public class StateLoaderImplConfig { + + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + + + @Bean(name = "stateLoaderImpl") + public StateLoaderImpl createIOperator() { + return new StateLoaderImpl(hazelcastServiceTest); + } +} diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/utils/JsonUtil.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/utils/JsonUtil.java new file mode 100644 index 000000000..2780f9465 --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/utils/JsonUtil.java @@ -0,0 +1,47 @@ +package ru.spcex.clearing.backendapi.controller.queue.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectReader; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static ru.spcex.clearing.backendapi.controller.queue.config.Jackson2HttpConverterConfig.JacksonObjectMapper.getMapper; + +public class JsonUtil { + + public static List readValues(String json, Class clazz) { + ObjectReader reader = getMapper().readerFor(clazz); + try { + return reader.readValues(json).readAll(); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid read array from JSON:\n'" + json + "'", e); + } + } + + public static T readValue(String json, Class clazz) { + try { + return getMapper().readValue(json, clazz); + } catch (IOException e) { + throw new IllegalArgumentException("Invalid read from JSON:\n'" + json + "'", e); + } + } + + public static String writeValue(T obj) { + try { + return getMapper().writeValueAsString(obj); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Invalid write to JSON:\n'" + obj + "'", e); + } + } + + public static String writeIgnoreProps(T obj, String... ignoreProps) { + Map map = getMapper().convertValue(obj, new TypeReference<>() { + }); + map.keySet().removeAll(Set.of(ignoreProps)); + return writeValue(map); + } +} \ No newline at end of file diff --git a/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/utils/MatcherFactory.java b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/utils/MatcherFactory.java new file mode 100644 index 000000000..1143b031a --- /dev/null +++ b/clearing-parent/backend-api/src/test/ru/spcex/clearing/backendapi/controller/queue/utils/MatcherFactory.java @@ -0,0 +1,82 @@ +package ru.spcex.clearing.backendapi.controller.queue.utils; + +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.ResultMatcher; + +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.function.BiConsumer; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Factory for creating test matchers. + *

+ * Comparing actual and expected objects via AssertJ + * Support converting json MvcResult to objects for comparation. + */ +public class MatcherFactory { + + public static Matcher usingAssertions(Class clazz, BiConsumer assertion, BiConsumer, Iterable> iterableAssertion) { + return new Matcher<>(clazz, assertion, iterableAssertion); + } + + public static Matcher usingEqualsComparator(Class clazz) { + return usingAssertions(clazz, + (a, e) -> assertThat(a).isEqualTo(e), + (a, e) -> assertThat(a).isEqualTo(e)); + } + + public static Matcher usingIgnoringFieldsComparator(Class clazz, String... fieldsToIgnore) { + return usingAssertions(clazz, + (a, e) -> assertThat(a).usingRecursiveComparison().ignoringFields(fieldsToIgnore).isEqualTo(e), + (a, e) -> assertThat(a).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(e)); + } + + public static class Matcher { + private final Class clazz; + private final BiConsumer assertion; + private final BiConsumer, Iterable> iterableAssertion; + + private Matcher(Class clazz, BiConsumer assertion, BiConsumer, Iterable> iterableAssertion) { + this.clazz = clazz; + this.assertion = assertion; + this.iterableAssertion = iterableAssertion; + } + + private static String getContent(MvcResult result) throws UnsupportedEncodingException { + return result.getResponse().getContentAsString(); + } + + public void assertMatch(T actual, T expected) { + assertion.accept(actual, expected); + } + + @SafeVarargs + public final void assertMatch(Iterable actual, T... expected) { + assertMatch(actual, List.of(expected)); + } + + public void assertMatch(Iterable actual, Iterable expected) { + iterableAssertion.accept(actual, expected); + } + + public ResultMatcher contentJson(T expected) { + return result -> assertMatch(JsonUtil.readValue(getContent(result), clazz), expected); + } + + @SafeVarargs + public final ResultMatcher contentJson(T... expected) { + return contentJson(List.of(expected)); + } + + public ResultMatcher contentJson(Iterable expected) { + return result -> assertMatch(JsonUtil.readValues(getContent(result), clazz), expected); + } + + public T readFromJson(ResultActions action) throws UnsupportedEncodingException { + return JsonUtil.readValue(getContent(action.andReturn()), clazz); + } + } +} diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java index dd47bd4fe..de4d5204b 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/base/TemplateMapStore.java @@ -9,7 +9,6 @@ import java.util.*; /** * MapStore для шаблонных бизнес-объектов - * @Component */ public abstract class TemplateMapStore extends ObjectBaseMapStore implements AutoconfiguredMap { @@ -22,13 +21,13 @@ public abstract class TemplateMapStore extends Object } /** - * * @return IMDGDistributedNames.* */ public abstract String getMapName(); /** * Список индексируемых полей, для быстрого поиска + * * @return */ public String[] getIndexingField() { @@ -37,6 +36,7 @@ public abstract class TemplateMapStore extends Object /** * Десериализатор + * * @param resultSet * @return */ @@ -51,6 +51,7 @@ public abstract class TemplateMapStore extends Object /** * Сериализатор + * * @param resultSet * @return Object[] args */ diff --git a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractUpdateMapService.java b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractUpdateMapService.java index 24a5bc55b..f90e5ee06 100644 --- a/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractUpdateMapService.java +++ b/clearing-parent/imdg/src/main/java/ru/spcex/clearing/imdg/services/AbstractUpdateMapService.java @@ -15,13 +15,11 @@ import java.time.Instant; public abstract class AbstractUpdateMapService implements InitializingBean, EntryAddedListener, EntryUpdatedListener, EntryRemovedListener { - private final Logger log = LoggerFactory.getLogger(this.getClass()); - - protected final String EVENT_CREATE="CREATE"; - protected final String EVENT_UPDATE="UPDATE"; - protected final String EVENT_DELETE="DELETE"; - + protected final String EVENT_CREATE = "CREATE"; + protected final String EVENT_UPDATE = "UPDATE"; + protected final String EVENT_DELETE = "DELETE"; protected final HazelcastInstance hazelcastServerInstance; + private final Logger log = LoggerFactory.getLogger(this.getClass()); public AbstractUpdateMapService(HazelcastInstance hazelcastServerInstance) { this.hazelcastServerInstance = hazelcastServerInstance; diff --git a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/enumeration/IEnumId.java b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/enumeration/IEnumId.java index a45b3c628..10859b6a4 100644 --- a/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/enumeration/IEnumId.java +++ b/platform-parent/platform-utils/src/main/java/ru/spcex/platform/utils/enumeration/IEnumId.java @@ -4,11 +4,7 @@ import java.io.Serializable; import java.util.Objects; public interface IEnumId extends Serializable { - Long getId(); - - default boolean equalsById(Long id) { - return id != null && getId().equals(id); - } + Long UNDEFINED_VALUE = Long.MIN_VALUE; /** * Проверяет что среди данного набора Enum, присутствует элемент с данным id @@ -46,7 +42,7 @@ public interface IEnumId extends Serializable { * Возвращает Enum по id, если в заданном классе такой определен * id может быть null * - * @return Enum если нашел, иначе null + * @return Enum если нашел, иначе null */ static & IEnumId> T getEnumById(Class enumClass, Long id) { for (T e : enumClass.getEnumConstants()) { @@ -60,5 +56,9 @@ public interface IEnumId extends Serializable { return enumVal == null ? null : enumVal.getId(); } - Long UNDEFINED_VALUE = Long.MIN_VALUE; + Long getId(); + + default boolean equalsById(Long id) { + return id != null && getId().equals(id); + } } diff --git a/pom.xml b/pom.xml index 270dfddac..3f2009995 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 @@ -30,8 +30,10 @@ ${folder_root_clearing_temp} - ${folder_root_clearing}/clearing-parent/backend-api - ${folder_root_clearing}/clearing-parent/securities-service + ${folder_root_clearing}/clearing-parent/backend-api + + ${folder_root_clearing}/clearing-parent/securities-service + ${folder_root_clearing}/clearing-parent/imdg ${folder_root_clearing}/clearing-parent/dbf-exporter ${folder_root_clearing}/clearing-parent/dbf-importer @@ -290,6 +292,14 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + + private + true + + \ No newline at end of file