From a8a4d991138dcef8e9d1a7b1af59c97c3211a512 Mon Sep 17 00:00:00 2001 From: psemenkov Date: Fri, 3 Mar 2023 18:13:19 +0300 Subject: [PATCH] Creating ClearingServiceTest for clearing-service. Fixing bug in ValidationConfig. --- clearing-parent/clearing-service/pom.xml | 9 +- .../clearing/config/ValidationConfig.java | 11 +- .../HazelcastServiceTestConfiguration.java | 71 +++++ .../clearing/config/KafkaConfigTest.java | 44 +++ .../PaymentInstructionCreatorConfigTest.java | 15 + .../clearing/service/ClearingServiceTest.java | 275 ++++++++++++++++++ .../spcex/clearing/utils/MatcherFactory.java | 38 +++ .../ru/spcex/clearing/utils/TestUtils.java | 142 +++++++++ 8 files changed, 598 insertions(+), 7 deletions(-) create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/KafkaConfigTest.java create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/PaymentInstructionCreatorConfigTest.java create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/ClearingServiceTest.java create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/MatcherFactory.java create mode 100644 clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/TestUtils.java diff --git a/clearing-parent/clearing-service/pom.xml b/clearing-parent/clearing-service/pom.xml index 1d7d1fd1a..c212e0834 100644 --- a/clearing-parent/clearing-service/pom.xml +++ b/clearing-parent/clearing-service/pom.xml @@ -1,6 +1,6 @@ - clearing-parent @@ -55,6 +55,11 @@ org.mockito mockito-core + + org.springframework.boot + spring-boot-starter-test + test + diff --git a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java index f420c0839..18854bb55 100644 --- a/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java +++ b/clearing-parent/clearing-service/src/main/java/ru/spcex/clearing/config/ValidationConfig.java @@ -2,6 +2,8 @@ package ru.spcex.clearing.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.account.AccountBalance; import ru.clearing.classes.statics.data.company.Company; import ru.clearing.classes.statics.data.company.relation.Relation; import ru.clearing.classes.statics.data.execution.ExecutionDeposit; @@ -24,14 +26,16 @@ import java.util.function.BiFunction; @Configuration public class ValidationConfig { private final Map> imdgs; + private final BiConsumer, String> addImdg = (context, s) + -> context.addImdg(s, getImdg(s)); public ValidationConfig(ImdgProvider imdgProvider) { this.imdgs = new HashMap<>(); BiConsumer> addImdg = (s, aClass) -> imdgs.put(s, imdgProvider.getImdg(s, aClass)); addImdg.accept(IMDGDistributedNames.Map_Relation, Relation.class); addImdg.accept(IMDGDistributedNames.Map_Company, Company.class); - addImdg.accept(IMDGDistributedNames.Map_Account, Company.class); - addImdg.accept(IMDGDistributedNames.Map_AccountBalance, Company.class); + addImdg.accept(IMDGDistributedNames.Map_Account, Account.class); + addImdg.accept(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class); } /** @@ -41,9 +45,6 @@ public class ValidationConfig { return imdgs.get(key); } - private final BiConsumer, String> addImdg = (context, s) - -> context.addImdg(s, getImdg(s)); - @Bean("executionDepositValidator") public BiFunction executionDepositValidator() { return (category, execDeposit) -> { diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java new file mode 100644 index 000000000..6fa6dea43 --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/HazelcastServiceTestConfiguration.java @@ -0,0 +1,71 @@ +package ru.spcex.clearing.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; +import java.util.concurrent.atomic.AtomicLong; + +@Configuration +public class HazelcastServiceTestConfiguration { + + public static final AtomicLong currentID = new AtomicLong(0L); + 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.getOrCreateHazelcastInstance(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/clearing-service/src/test/java/ru/spcex/clearing/config/KafkaConfigTest.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/KafkaConfigTest.java new file mode 100644 index 000000000..2ef297107 --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/KafkaConfigTest.java @@ -0,0 +1,44 @@ +package ru.spcex.clearing.config; + + +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.consumer.OffsetResetStrategy; +import org.apache.kafka.clients.producer.Producer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.service.RequestInfo; +import ru.spcex.clearing.platform.messaging.service.sender.KafkaSender; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgId; +import ru.spcex.platform.imdg.api.ImdgProvider; + +@Configuration +public class KafkaConfigTest { + + @Autowired + @Bean(name = "kafkaSenderTest") + public KafkaSender kafkaSender(Producer kafkaProducer, @Qualifier("hazelcastServiceTest") ImdgProvider imdgProvider) { + ImdgId imdgIdGenerator = imdgProvider.getImdgIdGenerator(); + return KafkaSender + .setup() + .producer(kafkaProducer) + .idGenerator(imdgIdGenerator::nextId) + .imdgProvider(s -> { + Imdg imdg = imdgProvider.getImdg(IMDGDistributedNames.Map_RequestInfo, RequestInfo.class); + return imdg::insert; + }) + .build(); + } + + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + @Bean(name = "mockConsumerTest") + public MockConsumer createConsumer() { + return new MockConsumer<>(OffsetResetStrategy.EARLIEST); + } + +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/PaymentInstructionCreatorConfigTest.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/PaymentInstructionCreatorConfigTest.java new file mode 100644 index 000000000..f7d1b3989 --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/config/PaymentInstructionCreatorConfigTest.java @@ -0,0 +1,15 @@ +package ru.spcex.clearing.config; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import ru.spcex.clearing.utils.TestUtils; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; + +public class PaymentInstructionCreatorConfigTest { + + @Bean(name = "paymentInstructionCreatorTest") + public TestUtils.PaymentInstructionCreatorTest createPaymentInstructionCreator(@Qualifier("hazelcastServiceTest") HazelcastService hazelcastServiceTest) { + return new TestUtils.PaymentInstructionCreatorTest(hazelcastServiceTest); + } + +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/ClearingServiceTest.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/ClearingServiceTest.java new file mode 100644 index 000000000..eedc1b745 --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/service/ClearingServiceTest.java @@ -0,0 +1,275 @@ +package ru.spcex.clearing.service; + +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import ru.clearing.classes.statics.data.account.Account; +import ru.clearing.classes.statics.data.account.AccountBalance; +import ru.clearing.classes.statics.data.company.Company; +import ru.clearing.classes.statics.data.company.relation.Relation; +import ru.clearing.classes.statics.data.execution.ExecutionDeposit; +import ru.clearing.classes.statics.data.generated.ClearingMemberCategory; +import ru.clearing.classes.statics.data.liabilities.LiabilitiesClaimsAssets; +import ru.clearing.classes.statics.data.liabilities.LiabilitiesClaimsMoney; +import ru.clearing.classes.statics.data.payment.PaymentInstruction; +import ru.spcex.clearing.config.*; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonIdRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.registry.DealRegisterNewRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.LauncherCommandRequest; +import ru.spcex.clearing.service.builder.LiabilitiesClaimsAssetsCreator; +import ru.spcex.clearing.service.builder.LiabilitiesClaimsMoneyCreator; +import ru.spcex.clearing.service.order.ExecutionDepositSorter; +import ru.spcex.clearing.service.order.PaymentInstructionSorter; +import ru.spcex.clearing.utils.MatcherFactory; +import ru.spcex.clearing.utils.TestUtils; +import ru.spcex.platform.enumeration.*; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService; +import ru.spcex.platform.utils.enumeration.IEnumKey; + +import javax.annotation.PostConstruct; +import java.math.BigDecimal; +import java.time.Instant; +import java.time.LocalDate; +import java.util.Collections; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; +import static ru.spcex.clearing.config.HazelcastServiceTestConfiguration.currentID; +import static ru.spcex.clearing.utils.MatcherFactory.usingIgnoringFieldsComparator; +import static ru.spcex.clearing.utils.TestUtils.addRecordToKafka; +import static ru.spcex.clearing.utils.TestUtils.getJsonStringForNew; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = { + SdfCreatorBySTLDPayment.class, + PaymentUpdateBySdf04.class, + VerificationResultComponent.class, + ExecutionDepositComponent.class, + ExecutionDepositSorter.class, + LiabilitiesClaimsAssetsCreator.class, + LiabilitiesClaimsMoneyCreator.class, + EventsReceiver.class, + ClearingService.class, + Clearing.class, + SortingConfig.class, + PaymentInstructionSorter.class, + MessageResolverConfig.class, + PaymentInstructionCreatorConfigTest.class, + ValidationConfig.class, + KafkaConfigTest.class, + HazelcastServiceTestConfiguration.class}) +class ClearingServiceTest { + public static final MatcherFactory.Matcher LIABILITIES_CLAIMS_ASSETS_MATCHER = usingIgnoringFieldsComparator("created", "updated"); + public static final MatcherFactory.Matcher LIABILITIES_CLAIMS_MONEY_MATCHER = usingIgnoringFieldsComparator("created", "updated"); + public static final MatcherFactory.Matcher PAYMENT_INSTRUCTION_MATCHER = usingIgnoringFieldsComparator("created", "updated"); + public static final MatcherFactory.Matcher EXECUTION_DEPOSIT_MATCHER = usingIgnoringFieldsComparator("created", "updated"); + private static final int PARTITION = 0; + private static final String TOPIC_START_CLEARING = Task.startOfClearing.topic(); + private static final String TOPIC_CONTINUE_CLEARING = Consts.CONTINUE_CLEARING; + private static final Long ID = currentID.getAndIncrement(); + + @Autowired + EventsReceiver eventsReceiver; + + @Autowired + LiabilitiesClaimsAssetsCreator lbltsClmsAssetsCreator; + + @Autowired + @Qualifier("paymentInstructionCreatorTest") + TestUtils.PaymentInstructionCreatorTest paymentInstructionCreator; + + @Autowired + LiabilitiesClaimsMoneyCreator lbltsClmsMoneyCreator; + + @Autowired + @Qualifier("hazelcastServiceTest") + private HazelcastService hazelcastServiceTest; + private Imdg executionDepositImdg; + private Imdg liabilitiesClaimsAssetsImdg; + private Imdg liabilitiesClaimsMoneyImdg; + private Imdg clearingCategoryImdg; + private Imdg relationImdg; + private Imdg companyImdg; + private Imdg accountImdg; + private Imdg accountBalanceImdg; + private ClearingCategory category; + private ExecutionDeposit executionDeposit; + + @Captor + private ArgumentCaptor producerRecord; + @SpyBean + private MockProducer mockProducer; + + @PostConstruct + private void init() { + hazelcastServiceTest.waitAvailable(); + this.executionDepositImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_ExecutionDeposit, ExecutionDeposit.class); + this.clearingCategoryImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_ClearingMemberCategory, ClearingMemberCategory.class); + this.liabilitiesClaimsAssetsImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_LiabilitiesClaimsAssets, LiabilitiesClaimsAssets.class); + this.liabilitiesClaimsMoneyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_LiabilitiesClaimsMoney, LiabilitiesClaimsMoney.class); + + this.relationImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Relation, Relation.class); + this.companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class); + this.accountImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Account, Account.class); + this.accountBalanceImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_AccountBalance, AccountBalance.class); + TestUtils.FutureRecordMetadata future = spy(TestUtils.FutureRecordMetadata.class); + doReturn(future).when(mockProducer).send(producerRecord.capture()); + } + + /** + * {@link ClearingService#executeClearing()}
+ * Тест проверяет создание сущности {@link LauncherCommandRequest} в Hazelcast при передаче из Apache Kafka.
+ */ + @Test + void startClearingNew() { + //ARRANGE + Long companyIdI1 = 11L; + Long relationIdI1 = 111L; + Long accountIdI1 = 1111L; + Long securityIdI1 = 11111L; + LocalDate firstSettlementDateI1 = LocalDate.now(); + LocalDate secondSettlementDateI2 = LocalDate.ofYearDay(2022, 31); + + preparOptimisticCase(companyIdI1, relationIdI1, accountIdI1, + securityIdI1, firstSettlementDateI1, secondSettlementDateI2, "I"); + + //ACT + //stage executeClearing(startClearing) + addRecordToKafka((MockConsumer) eventsReceiver.getConsumer(), TOPIC_START_CLEARING, PARTITION, 0, getJsonStringForNew(new DealRegisterNewRequest(), ID)); + + //waiting for kafka producer send message + verify(mockProducer, timeout(230_000L).times(1)) + .send(producerRecord.capture()); + assertEquals(Consts.BALANCE_ACCOUNT_UPDATE, producerRecord.getValue().topic()); + BaseRequest baseRequestResult = (BaseRequest) producerRecord.getValue().value(); + + //stage continueClearing + CommonIdRequest requestPayload = new CommonIdRequest(); + requestPayload.setId(baseRequestResult.getId()); + addRecordToKafka((MockConsumer) eventsReceiver.getConsumer(), TOPIC_CONTINUE_CLEARING, PARTITION, 0, getJsonStringForNew(requestPayload, ID)); + + //waiting for kafka producer send message (finale event) + verify(mockProducer, timeout(230_000L).times(2)) + .send(producerRecord.capture()); + + //ASSERT + assertEquals(Task.createOrder.topic(), producerRecord.getValue().topic()); + + //First LiabilitiesClaimsAssets && LiabilitiesClaimsMoney + LiabilitiesClaimsAssets resultFirstClaimsAssets = liabilitiesClaimsAssetsImdg.getSingleObjectByFieldValues( + Map.of("accountId", accountIdI1, "settlementDate", firstSettlementDateI1)); + LiabilitiesClaimsMoney resultFirstClaimsMoney = liabilitiesClaimsMoneyImdg.getSingleObjectByFieldValues( + Map.of("accountId", accountIdI1, "settlementDate", firstSettlementDateI1)); + LiabilitiesClaimsAssets predictableFirstClaimsAssets = lbltsClmsAssetsCreator.createFirstLegLCA(category, executionDeposit); + predictableFirstClaimsAssets.setId(resultFirstClaimsAssets.getId()); + predictableFirstClaimsAssets.setPaymentId(resultFirstClaimsAssets.getPaymentId()); + predictableFirstClaimsAssets.setLiabilitiesClaimsMoneyId(resultFirstClaimsMoney.getId()); + LiabilitiesClaimsMoney predictableFirstClaimsMoney = lbltsClmsMoneyCreator.createFirstLegLcm(predictableFirstClaimsAssets, category); + predictableFirstClaimsMoney.setId(resultFirstClaimsMoney.getId()); + LIABILITIES_CLAIMS_ASSETS_MATCHER.assertMatch(resultFirstClaimsAssets, predictableFirstClaimsAssets); + LIABILITIES_CLAIMS_MONEY_MATCHER.assertMatch(resultFirstClaimsMoney, predictableFirstClaimsMoney); + //Second LiabilitiesClaimsAssets && LiabilitiesClaimsMoney + LiabilitiesClaimsAssets resultSecondClaimsAssets = liabilitiesClaimsAssetsImdg.getSingleObjectByFieldValues( + Map.of("accountId", accountIdI1, "settlementDate", secondSettlementDateI2)); + LiabilitiesClaimsMoney resultSecondClaimsMoney = liabilitiesClaimsMoneyImdg.getSingleObjectByFieldValues( + Map.of("accountId", accountIdI1, "settlementDate", secondSettlementDateI2)); + LiabilitiesClaimsAssets predictableSecondClaimsAssets = lbltsClmsAssetsCreator.createSecondLegLCA(category, executionDeposit); + predictableSecondClaimsAssets.setId(resultSecondClaimsAssets.getId()); + predictableSecondClaimsAssets.setLiabilitiesClaimsMoneyId(resultSecondClaimsMoney.getId()); + LiabilitiesClaimsMoney predictableSecondClaimsMoney = lbltsClmsMoneyCreator.createSecondLegLcm(predictableSecondClaimsAssets, category); + predictableSecondClaimsMoney.setId(resultSecondClaimsMoney.getId()); + LIABILITIES_CLAIMS_ASSETS_MATCHER.assertMatch(resultSecondClaimsAssets, predictableSecondClaimsAssets); + LIABILITIES_CLAIMS_MONEY_MATCHER.assertMatch(resultSecondClaimsMoney, predictableSecondClaimsMoney); + //PaymentInstruction + PaymentInstruction resultPaymentInstruction = paymentInstructionCreator.searchExistPaymentInstructionsFirstI(predictableFirstClaimsAssets); + PaymentInstruction predictablePaymentInstruction = paymentInstructionCreator.createPaymentInstruction(executionDeposit, predictableFirstClaimsAssets, Collections.singleton(category)); + predictablePaymentInstruction.setId(resultPaymentInstruction.getId()); + predictablePaymentInstruction.setDocumentNumber(resultPaymentInstruction.getDocumentNumber()); + PAYMENT_INSTRUCTION_MATCHER.assertMatch(resultPaymentInstruction, predictablePaymentInstruction); + //ExecutionDeposit + ExecutionDeposit resultExecutionDeposit = executionDepositImdg.getSingleObjectByFieldValues( + Map.of("accountId", accountIdI1, "securityId", securityIdI1)); + executionDeposit.setSessionId(resultExecutionDeposit.getSessionId()); + EXECUTION_DEPOSIT_MATCHER.assertMatch(resultExecutionDeposit, executionDeposit); + } + + void preparOptimisticCase(Long companyId, Long relationId, Long accountId, + Long securityId, LocalDate dtF, LocalDate dtS, String memberCategory) { + category = IEnumKey.getEnumByKey(ClearingCategory.class, memberCategory); + + executionDeposit = getExecutionDeposit(companyId, accountId, securityId, dtF, dtS); + executionDepositImdg.insert(executionDeposit); + + ClearingMemberCategory clearingMemberCategory = new ClearingMemberCategory(); + clearingMemberCategory.setCompanyId(companyId); + clearingMemberCategory.setClearingMemberCategory(memberCategory); + clearingCategoryImdg.insert(clearingMemberCategory); + + Relation relation = new Relation(); + relation.setId(relationId); + relation.setConsumerId(companyId); + relation.setServiceStatus(ServiceStatus.Active.getKey()); + relationImdg.insert(relation); + + Account account = new Account(); + account.setId(accountId); + account.setRelationId(relationId); + account.setAccountStatus(AccountStatus.ACTIVE.getKey()); + accountImdg.insert(account); + + Company company = new Company(); + company.setId(companyId); + company.setWorkflowStatus(WorkflowStatus.Active.getKey()); + companyImdg.insert(company); + + AccountBalance accountBalance = new AccountBalance(); + accountBalance.setAccountId(accountId); + accountBalance.setCompanyId(companyId); + accountBalanceImdg.insert(accountBalance); + } + + ExecutionDeposit getExecutionDeposit(Long companyId, Long accountId, Long securityId, LocalDate dtF, LocalDate dtS) { + ExecutionDeposit executionDeposit = new ExecutionDeposit(); + executionDeposit.setExchangeExecutionId(5L); + executionDeposit.setExchangeExecutionTime(Instant.now()); + executionDeposit.setTradingDate(LocalDate.now()); + executionDeposit.setAccountId(accountId); + executionDeposit.setMarket("market"); + executionDeposit.setPrice(new BigDecimal(9)); + executionDeposit.setLots(new BigDecimal(0)); + executionDeposit.setQuantity(new BigDecimal(8)); + executionDeposit.setFirstLegAmount(new BigDecimal(7)); + executionDeposit.setSecondLegAmount(new BigDecimal(6)); + executionDeposit.setInterestAmount(new BigDecimal(5)); + executionDeposit.setSide("side"); + executionDeposit.setSettlementCurrency("settlement"); + executionDeposit.setCompanyId(companyId); + executionDeposit.setDuration(1L); + executionDeposit.setFirstLegSettlementDate(dtF); + executionDeposit.setSecondLegSettlementDate(dtS); + executionDeposit.setFirstLegSettlementCode(LocalDate.now()); + executionDeposit.setSecondLegSettlementCode(LocalDate.now()); + executionDeposit.setSecurityFullName("full"); + executionDeposit.setSecuritySymbol("symbol"); + executionDeposit.setSecurityId(securityId); + executionDeposit.setCounterPartyId(0L); + executionDeposit.setCoverageStatus(Allowed.ALLOWED.getKey()); + executionDeposit.setSessionId(null); + executionDeposit.setClearingDate(LocalDate.now()); + return executionDeposit; + } +} \ No newline at end of file diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/MatcherFactory.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/MatcherFactory.java new file mode 100644 index 000000000..1141f3840 --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/MatcherFactory.java @@ -0,0 +1,38 @@ +package ru.spcex.clearing.utils; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Factory for creating test matchers. + *

+ * Comparing actual and expected objects via AssertJ + */ +public class MatcherFactory { + + public static Matcher usingIgnoringFieldsComparator(String... fieldsToIgnore) { + return new Matcher<>(fieldsToIgnore); + } + + public static class Matcher { + private final String[] fieldsToIgnore; + + private Matcher(String... fieldsToIgnore) { + this.fieldsToIgnore = fieldsToIgnore; + } + + public void assertMatch(T actual, T expected) { + assertThat(actual).usingRecursiveComparison().ignoringFields(fieldsToIgnore).isEqualTo(expected); + } + + @SafeVarargs + public final void assertMatch(Iterable actual, T... expected) { + assertMatch(actual, Arrays.asList(expected)); + } + + public void assertMatch(Iterable actual, Iterable expected) { + assertThat(actual).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(expected); + } + } +} diff --git a/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/TestUtils.java b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/TestUtils.java new file mode 100644 index 000000000..acc01344c --- /dev/null +++ b/clearing-parent/clearing-service/src/test/java/ru/spcex/clearing/utils/TestUtils.java @@ -0,0 +1,142 @@ +package ru.spcex.clearing.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.apache.kafka.common.TopicPartition; +import org.mockito.ArgumentCaptor; +import ru.clearing.classes.statics.data.execution.ExecutionDeposit; +import ru.clearing.classes.statics.data.liabilities.LiabilitiesClaimsAssets; +import ru.clearing.classes.statics.data.payment.PaymentInstruction; +import ru.spcex.clearing.platform.messaging.domain.ActionType; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; +import ru.spcex.clearing.service.builder.PaymentInstructionCreator; +import ru.spcex.platform.classes.base.SpcexObjectBase; +import ru.spcex.platform.enumeration.ClearingCategory; +import ru.spcex.platform.imdg.api.Imdg; +import ru.spcex.platform.imdg.api.ImdgProvider; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static ru.spcex.clearing.platform.messaging.service.Status.Success; +import static ru.spcex.clearing.utils.MatcherFactory.usingIgnoringFieldsComparator; + +public class TestUtils { + public static final MatcherFactory.Matcher> BASE_REQUEST_MATCHER = usingIgnoringFieldsComparator(); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static void waitingWhenAddedRecordAndCheckIt(Long id, MockProducer mockProducer, ArgumentCaptor producerRecord) { + BaseRequest predictableBaseRequest = new BaseRequest<>(); + predictableBaseRequest.setId(id); + predictableBaseRequest.setActionType(ActionType.SYSTEM); + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + requestInfoUpdate.setId(id); + requestInfoUpdate.setStatus(Success); + predictableBaseRequest.setRequestPayload(requestInfoUpdate); + + //waiting for kafka producer send message (finale event) + verify(mockProducer, timeout(30_000L).times(1)) + .send(producerRecord.capture()); + + BaseRequest baseRequestResult = (BaseRequest) producerRecord.getValue().value(); + assertEquals(Consts.REQUEST_INFO_UPDATE, producerRecord.getValue().topic()); + BASE_REQUEST_MATCHER.assertMatch(baseRequestResult, predictableBaseRequest); + } + + public static void addRecordToKafka(MockConsumer mockConsumer, String topic, int partition, long offset, String jsonValue) { + TopicPartition tp = new TopicPartition(topic, partition); + HashMap startOffsets = new HashMap<>(); + startOffsets.put(tp, 0L); + mockConsumer.updateBeginningOffsets(startOffsets); + mockConsumer.schedulePollTask(() -> { + mockConsumer.rebalance(Collections.singletonList(tp)); + mockConsumer.addRecord(new ConsumerRecord<>(topic, partition, offset, "key", jsonValue)); + }); + } + + public static String getJsonStringForNew(T accountRequest, long id) { + return getJsonBaseRequest(accountRequest, id, ActionType.NEW); + } + + public static String getJsonStringForUPDATE(T accountRequest, long id) { + return getJsonBaseRequest(accountRequest, id, ActionType.UPDATE); + } + + public static String getJsonStringForDELETE(T accountRequest, long id) { + return getJsonBaseRequest(accountRequest, id, ActionType.DELETE); + } + + private static String getJsonBaseRequest(T accountRequest, long id, ActionType actionType) { + BaseRequest baseRequest = new BaseRequest<>(); + baseRequest.setRequestPayload(accountRequest); + baseRequest.setId(id); + baseRequest.setActionType(actionType); + String jsonBaseRequest; + try { + jsonBaseRequest = objectMapper.writeValueAsString(baseRequest); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return jsonBaseRequest; + } + + public static void clearAllInImdg(Imdg imdg) { + Collection values = imdg.getAllValues(); + values.forEach(imdg::delete); + } + + public static class FutureRecordMetadata implements Future { + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return false; + } + + @Override + public RecordMetadata get() throws InterruptedException, ExecutionException { + return null; + } + + @Override + public RecordMetadata get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return null; + } + } + + public static class PaymentInstructionCreatorTest extends PaymentInstructionCreator { + public PaymentInstructionCreatorTest(ImdgProvider imdgProvider) { + super(imdgProvider); + } + + public PaymentInstruction createPaymentInstruction(ExecutionDeposit executionDeposit, LiabilitiesClaimsAssets liabilitiesClaimsAssets, + Collection clearingCategory) { + List list = super.createPaymentInstructions(executionDeposit, liabilitiesClaimsAssets, clearingCategory); + return list.stream().findFirst().orElseGet(PaymentInstruction::new); + } + } +}