Merge branch 'psemenkov' into dev

This commit is contained in:
etreshenkov 2022-10-27 14:48:26 +03:00
commit c5b9cdc0a7
15 changed files with 1413 additions and 4 deletions

View file

@ -36,6 +36,27 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@ -63,6 +84,23 @@
<finalName>${project.artifactId}</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.2.0-M1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0-M1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

View file

@ -55,6 +55,7 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
bankAccount.setDestination(req.getDestination());
bankAccount.setTaxpayerIdentificationNumber(req.getTaxpayerIdentificationNumber());
bankAccount.setTaxRegistrationReasonCode(req.getTaxRegistrationReasonCode());
bankAccount.setAccount(req.getAccount());
bankAccountMap.insert(bankAccount);
log.debug("successfully processed, new id {}", bankAccount.getId());
@ -72,14 +73,19 @@ public class BankAccountService extends QueueConsumer implements InitializingBea
bankAccount.setDestination(req.getDestination());
bankAccount.setTaxpayerIdentificationNumber(req.getTaxpayerIdentificationNumber());
bankAccount.setTaxRegistrationReasonCode(req.getTaxRegistrationReasonCode());
bankAccount.setAccount(req.getAccount());
bankAccountMap.update(bankAccount);
log.debug("successfully update, existing bankAccount with id {}", bankAccount.getId());
}
private void bankAccountDelete(BaseRequest<CommonDeleteRequest> userRequest) {
CommonDeleteRequest req = userRequest.getRequestPayload();
log.debug("CommonDeleteRequest received id = {}", req.getId());
BankAccount bankAccount = bankAccountMap.getSingleObjectByID(req.getId());
bankAccountMap.delete(bankAccount);
log.debug("successfully delete, existing bankAccount with id {}", bankAccount.getId());
}
}

View file

@ -0,0 +1,68 @@
package ru.spcex.clearing.account.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;
}
}

View file

@ -0,0 +1,332 @@
package ru.spcex.clearing.account.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.IMap;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.TopicPartition;
import org.junit.jupiter.api.Assertions;
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.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.account.BankAccount;
import ru.spcex.clearing.account.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.account.utils.MatcherFactory.Matcher;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
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.domain.cud.account.BankAccountNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountUpdateRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.util.Collections;
import java.util.HashMap;
import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFieldsComparator;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
public class BankAccountServiceTest {
public static final Matcher<BankAccount> BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator("id");
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;
private static final String TOPIC_ACCOUNT_DELETE = Consts.DESTINATION_BANK_ACCOUNT_DELETE;
private static Long currentId = 0L;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
/**
* {@link BankAccountService#bankAccountNew(BaseRequest request)}<br>
* Тест проверяет генерацию сущности {@link BankAccount} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link BankAccountNewRequest}:<br>
* {@link BankAccountNewRequest#bankIdentificationCode} - 99999<br>
* {@link BankAccountNewRequest#bankName} - ооо тинькофф<br>
* {@link BankAccountNewRequest#correspondentAccount} - 9294189285498598598<br>
* {@link BankAccountNewRequest#correspondentAccountName} - BIK OF<br>
* {@link BankAccountNewRequest#currency} - RUB<br>
* {@link BankAccountNewRequest#destination} - OOO ROGA I KOPITA<br>
* {@link BankAccountNewRequest#taxpayerIdentificationNumber} - 848484848484<br>
* {@link BankAccountNewRequest#taxRegistrationReasonCode} - 886886<br>
* {@link BankAccountNewRequest#account} - 123456789123<br>
*/
@Test
public void bankAccountNew() throws InterruptedException {
//arrange
BankAccountNewRequest bankAccountNewRequest = new BankAccountNewRequest();
bankAccountNewRequest.setBankName("ooo tinkoff");
bankAccountNewRequest.setBankIdentificationCode("99999");
bankAccountNewRequest.setCorrespondentAccount("9294189285498598598");
bankAccountNewRequest.setCorrespondentAccountName("BIK OF TINKOFF");
bankAccountNewRequest.setCurrency("RUB");
bankAccountNewRequest.setDestination("OOO ROGA I KOPITA");
bankAccountNewRequest.setTaxpayerIdentificationNumber("848484848484");
bankAccountNewRequest.setTaxRegistrationReasonCode("886886");
bankAccountNewRequest.setAccount("123456789123");
BaseRequest<BankAccountNewRequest> baseNewRequest = new BaseRequest<>();
baseNewRequest.setRequestPayload(bankAccountNewRequest);
baseNewRequest.setId(currentId);
baseNewRequest.setActionType(ActionType.NEW);
String jsonBaseNewRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseNewRequest = objectMapper.writeValueAsString(baseNewRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
BankAccount predictableResult = new BankAccount();
predictableResult.setBankName("ooo tinkoff");
predictableResult.setBankIdentificationCode("99999");
predictableResult.setCorrespondentAccount("9294189285498598598");
predictableResult.setCorrespondentAccountName("BIK OF TINKOFF");
predictableResult.setCurrency("RUB");
predictableResult.setDestination("OOO ROGA I KOPITA");
predictableResult.setTaxpayerIdentificationNumber("848484848484");
predictableResult.setTaxRegistrationReasonCode("886886");
predictableResult.setAccount("123456789123");
predictableResult.setId(currentId);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_ACCOUNT_NEW, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_ACCOUNT_NEW, PARTITION, 0, "key", jsonBaseNewRequest));
});
HashMap<TopicPartition, Long> startOffsets = new HashMap<>();
TopicPartition tp = new TopicPartition(TOPIC_ACCOUNT_NEW, PARTITION);
startOffsets.put(tp, 0L);
mockConsumer.updateBeginningOffsets(startOffsets);
//ACT
//service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, hazelcastServiceTest);
Thread.sleep(10000);
//callbacks set up
bankAccountService.afterPropertiesSet();
Thread.sleep(10000);
//ASSERT
IMap<Long, BankAccount> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_BankAccount);
BankAccount result = iMap.get(currentId);
BANK_ACCOUNT_MATCHER.assertMatch(result, predictableResult);
//reset hazelcastService for next test
iMap.clear();
currentId++;
}
/**
* {@link BankAccountService#bankAccountUpdate(BaseRequest)}<br>
* Тест проверяет обновление сущности {@link BankAccount} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link BankAccountUpdateRequest}:<br>
* {@link BankAccountUpdateRequest#bankIdentificationCode} - NEW BUNK NAME<br>
* {@link BankAccountUpdateRequest#bankName} - 88888<br>
* {@link BankAccountUpdateRequest#correspondentAccount} - 894984646541316<br>
* {@link BankAccountUpdateRequest#correspondentAccountName} - BIK OF NEW BUNK<br>
* {@link BankAccountUpdateRequest#currency} - EU<br>
* {@link BankAccountUpdateRequest#destination} - OOO NEW BUNK<br>
* {@link BankAccountUpdateRequest#taxpayerIdentificationNumber} - 65468461321<br>
* {@link BankAccountUpdateRequest#taxRegistrationReasonCode} - 532137<br>
* {@link BankAccountUpdateRequest#account} - 326984656514<br>
*/
@Test
void bankAccountUpdate() throws InterruptedException {
//arrange
BankAccountNewRequest bankAccountNewRequest = new BankAccountNewRequest();
bankAccountNewRequest.setBankName("ooo tinkoff");
bankAccountNewRequest.setBankIdentificationCode("99999");
bankAccountNewRequest.setCorrespondentAccount("9294189285498598598");
bankAccountNewRequest.setCorrespondentAccountName("BIK OF TINKOFF");
bankAccountNewRequest.setCurrency("RUB");
bankAccountNewRequest.setDestination("OOO ROGA I KOPITA");
bankAccountNewRequest.setTaxpayerIdentificationNumber("848484848484");
bankAccountNewRequest.setTaxRegistrationReasonCode("886886");
bankAccountNewRequest.setAccount("123456789123");
BaseRequest<BankAccountNewRequest> baseNewRequest = new BaseRequest<>();
baseNewRequest.setRequestPayload(bankAccountNewRequest);
baseNewRequest.setId(currentId);
baseNewRequest.setActionType(ActionType.NEW);
String jsonBaseNewRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseNewRequest = objectMapper.writeValueAsString(baseNewRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
BankAccountUpdateRequest bankAccountUpdateRequest = new BankAccountUpdateRequest();
bankAccountUpdateRequest.setId(currentId);
bankAccountUpdateRequest.setBankName("NEW BUNK NAME");
bankAccountUpdateRequest.setBankIdentificationCode("88888");
bankAccountUpdateRequest.setCorrespondentAccount("894984646541316");
bankAccountUpdateRequest.setCorrespondentAccountName("BIK OF NEW BUNK");
bankAccountUpdateRequest.setCurrency("EU");
bankAccountUpdateRequest.setDestination("OOO NEW BUNK");
bankAccountUpdateRequest.setTaxpayerIdentificationNumber("65468461321");
bankAccountUpdateRequest.setTaxRegistrationReasonCode("532137");
bankAccountUpdateRequest.setAccount("326984656514");
BaseRequest<BankAccountUpdateRequest> baseUpdateRequest = new BaseRequest<>();
baseUpdateRequest.setRequestPayload(bankAccountUpdateRequest);
baseUpdateRequest.setId(currentId);
baseUpdateRequest.setActionType(ActionType.UPDATE);
String jsonBaseUpdateRequest;
try {
jsonBaseUpdateRequest = objectMapper.writeValueAsString(baseUpdateRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
BankAccount predictableUpdateResult = new BankAccount();
predictableUpdateResult.setBankName("NEW BUNK NAME");
predictableUpdateResult.setBankIdentificationCode("88888");
predictableUpdateResult.setCorrespondentAccount("894984646541316");
predictableUpdateResult.setCorrespondentAccountName("BIK OF NEW BUNK");
predictableUpdateResult.setCurrency("EU");
predictableUpdateResult.setDestination("OOO NEW BUNK");
predictableUpdateResult.setTaxpayerIdentificationNumber("65468461321");
predictableUpdateResult.setTaxRegistrationReasonCode("532137");
predictableUpdateResult.setAccount("326984656514");
predictableUpdateResult.setId(currentId);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_ACCOUNT_NEW, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_ACCOUNT_NEW, PARTITION, 0, "key", jsonBaseNewRequest));
});
HashMap<TopicPartition, Long> startOffsets = new HashMap<>();
TopicPartition tp = new TopicPartition(TOPIC_ACCOUNT_NEW, PARTITION);
startOffsets.put(tp, 0L);
mockConsumer.updateBeginningOffsets(startOffsets);
//ACT
//service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, hazelcastServiceTest);
Thread.sleep(10000);
//callbacks set up
bankAccountService.afterPropertiesSet();
Thread.sleep(10000);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_ACCOUNT_UPDATE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_ACCOUNT_UPDATE, PARTITION, 0, "key", jsonBaseUpdateRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpUpdating = new TopicPartition(TOPIC_ACCOUNT_UPDATE, PARTITION);
startOffsetsUpdating.put(tpUpdating, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//ASSERT
Thread.sleep(10000);
IMap<Long, BankAccount> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_BankAccount);
BankAccount resultUpdating = iMap.get(currentId);
BANK_ACCOUNT_MATCHER.assertMatch(resultUpdating, predictableUpdateResult);
//reset hazelcastService for next test
iMap.clear();
currentId++;
}
/**
* {@link BankAccountService#bankAccountDelete(BaseRequest)}
* Тест проверяет удаление сущности {@link BankAccount} в Hazelcast при передаче из Apache Kafka.
* Входной запрос {@link CommonDeleteRequest}:
* {@link CommonDeleteRequest#id} - Идентификатор записи
*/
@Test
void bankAccountDelete() throws InterruptedException {
//arrange
BankAccountNewRequest bankAccountNewRequest = new BankAccountNewRequest();
bankAccountNewRequest.setBankName("ooo tinkoff");
bankAccountNewRequest.setBankIdentificationCode("99999");
bankAccountNewRequest.setCorrespondentAccount("9294189285498598598");
bankAccountNewRequest.setCorrespondentAccountName("BIK OF TINKOFF");
bankAccountNewRequest.setCurrency("RUB");
bankAccountNewRequest.setDestination("OOO ROGA I KOPITA");
bankAccountNewRequest.setTaxpayerIdentificationNumber("848484848484");
bankAccountNewRequest.setTaxRegistrationReasonCode("886886");
bankAccountNewRequest.setAccount("123456789123");
BaseRequest<BankAccountNewRequest> baseNewRequest = new BaseRequest<>();
baseNewRequest.setRequestPayload(bankAccountNewRequest);
baseNewRequest.setId(currentId);
baseNewRequest.setActionType(ActionType.NEW);
String jsonBaseNewRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseNewRequest = objectMapper.writeValueAsString(baseNewRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
CommonDeleteRequest commonDeleteRequest = new CommonDeleteRequest();
commonDeleteRequest.setId(currentId);
BaseRequest<CommonDeleteRequest> baseDeleteRequest = new BaseRequest<>();
baseDeleteRequest.setRequestPayload(commonDeleteRequest);
baseDeleteRequest.setId(currentId);
baseDeleteRequest.setActionType(ActionType.DELETE);
String jsonDeleteNewRequest;
try {
jsonDeleteNewRequest = objectMapper.writeValueAsString(baseDeleteRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_ACCOUNT_NEW, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_ACCOUNT_NEW, PARTITION, 0, "key", jsonBaseNewRequest));
});
HashMap<TopicPartition, Long> startOffsets = new HashMap<>();
TopicPartition tp = new TopicPartition(TOPIC_ACCOUNT_NEW, PARTITION);
startOffsets.put(tp, 0L);
mockConsumer.updateBeginningOffsets(startOffsets);
//ACT
//service set up
BankAccountService bankAccountService = new BankAccountService(mockConsumer, hazelcastServiceTest);
Thread.sleep(10000);
//callbacks set up
bankAccountService.afterPropertiesSet();
Thread.sleep(10000);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_ACCOUNT_DELETE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_ACCOUNT_DELETE, PARTITION, 0, "key", jsonDeleteNewRequest));
});
HashMap<TopicPartition, Long> startOffsetsDeleting = new HashMap<>();
TopicPartition tpDeleting = new TopicPartition(TOPIC_ACCOUNT_DELETE, PARTITION);
startOffsetsDeleting.put(tpDeleting, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsDeleting);
//ASSERT
Thread.sleep(10000);
IMap<Long, BankAccount> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_BankAccount);
Assertions.assertEquals(0, iMap.size());
//reset hazelcastService for next test
iMap.clear();
currentId++;
}
}

View file

@ -0,0 +1,38 @@
package ru.spcex.clearing.account.utils;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Factory for creating test matchers.
* <p>
* Comparing actual and expected objects via AssertJ
*/
public class MatcherFactory {
public static <T> Matcher<T> usingIgnoringFieldsComparator(String... fieldsToIgnore) {
return new Matcher<>(fieldsToIgnore);
}
public static class Matcher<T> {
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<T> actual, T... expected) {
assertMatch(actual, Arrays.asList(expected));
}
public void assertMatch(Iterable<T> actual, Iterable<T> expected) {
assertThat(actual).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(expected);
}
}
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>clearing-parent</artifactId>
@ -36,6 +36,11 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@ -63,6 +68,23 @@
<finalName>${project.artifactId}</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.2.0-M1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0-M1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

View file

@ -41,7 +41,7 @@ public class CompanySymbolService extends QueueConsumer implements InitializingB
CompanySymbolUpdateRequest req = userRequest.getRequestPayload();
log.debug("CompanySymbolUpdateRequest received");
CompanySymbols companySymbols = companySymbolsMap.getSingleObjectByID(req.getId());
companySymbols.setCompanySymbol(req.getCompanySymbol());
// companySymbols.setCompanySymbol(req.getCompanySymbol()); по ТЗ не должен менятся при обновлении
companySymbols.setCompanySymbolValue(req.getCompanySymbolValue());
companySymbolsMap.update(companySymbols);

View file

@ -6,6 +6,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
@ -15,6 +16,7 @@ import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
@Service
public class ContactService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Contact> contactMap;
@ -38,7 +40,7 @@ public class ContactService extends QueueConsumer implements InitializingBean {
ContactUpdateRequest req = userRequest.getRequestPayload();
log.debug("ContactUpdateRequest received");
Contact contact = contactMap.getSingleObjectByID(req.getId());
contact.setContactType(req.getContactType());
// contact.setContactType(req.getContactType()); по ТЗ не должен менятся при обновлении
contact.setContactValue(req.getContactValue());
contactMap.update(contact);

View file

@ -0,0 +1,68 @@
package ru.spcex.clearing.company.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;
}
}

View file

@ -0,0 +1,211 @@
package ru.spcex.clearing.company.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryRemovedListener;
import com.hazelcast.map.listener.EntryUpdatedListener;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.TopicPartition;
import org.junit.jupiter.api.Assertions;
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.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.company.utils.MatcherFactory.Matcher;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
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.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ClearingMemberCategoryUpdateRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.util.Collections;
import java.util.HashMap;
import static ru.spcex.clearing.company.utils.MatcherFactory.usingIgnoringFieldsComparator;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
class ClearingMemberCategoryServiceTest {
public static final Matcher<ClearingMemberCategory> MEMBER_CATEGORY_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_MEMBER_CATEGORY_UPDATE = Consts.DESTINATION_CLEARING_MEMBER_CATEGORY_UPDATE;
private static final String TOPIC_MEMBER_CATEGORY_DELETE = Consts.DESTINATION_CLEARING_MEMBER_CATEGORY_DELETE;
private static final Long ID = 0L;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
/**
* {@link ClearingMemberCategoryService#clearingMemberCategoryUpdate(BaseRequest)}<br>
* Тест проверяет обновление сущности {@link ClearingMemberCategory} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link ClearingMemberCategoryUpdateRequest}:<br>
* {@link ClearingMemberCategoryUpdateRequest#id} - Идентификатор записи<br>
* {@link ClearingMemberCategoryUpdateRequest#clearingMemberCategory} - 1234<br>
*/
@Test
void clearingMemberCategoryUpdate() throws InterruptedException {
//ARRANGE
ClearingMemberCategory existsСlearingMemberCategory = new ClearingMemberCategory();
existsСlearingMemberCategory.setId(ID);
existsСlearingMemberCategory.setClearingMemberCategory("0000");
ClearingMemberCategoryUpdateRequest memberCategoryUpdateRequest = new ClearingMemberCategoryUpdateRequest();
memberCategoryUpdateRequest.setId(ID);
memberCategoryUpdateRequest.setClearingMemberCategory("1234");
BaseRequest<ClearingMemberCategoryUpdateRequest> baseUpdateRequest = new BaseRequest<>();
baseUpdateRequest.setRequestPayload(memberCategoryUpdateRequest);
baseUpdateRequest.setId(ID);
baseUpdateRequest.setActionType(ActionType.UPDATE);
String jsonBaseForUpdatingRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseForUpdatingRequest = objectMapper.writeValueAsString(baseUpdateRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
ClearingMemberCategory predictableClearingMemberCategory = new ClearingMemberCategory();
predictableClearingMemberCategory.setId(ID);
predictableClearingMemberCategory.setClearingMemberCategory("1234");
//ACT
//service set up
ClearingMemberCategoryService clearingMemberCategoryService = new ClearingMemberCategoryService(mockConsumer, hazelcastServiceTest);
//callbacks set up
clearingMemberCategoryService.afterPropertiesSet();
IMap<Long, ClearingMemberCategory> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_ClearingMemberCategory);
iMap.put(ID, existsСlearingMemberCategory);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_MEMBER_CATEGORY_UPDATE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_MEMBER_CATEGORY_UPDATE, PARTITION, 0, "key", jsonBaseForUpdatingRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpUpdating = new TopicPartition(TOPIC_MEMBER_CATEGORY_UPDATE, PARTITION);
startOffsetsUpdating.put(tpUpdating, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//waiting for hazelcast map item updates
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryUpdatedListener<Long, Contact>) entryEvent -> {
System.out.println("Checking If removed..");
synchronized (waiter) {
try {
waiter.wait(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
waiter.notify();
}
}, false);
synchronized (waiter) {
waiter.wait(100);
}
//ASSERT
ClearingMemberCategory resultUpdating = iMap.get(ID);
MEMBER_CATEGORY_MATCHER.assertMatch(resultUpdating, predictableClearingMemberCategory);
//preparing hazelcastImdgProvider for next test
iMap.removeEntryListener(listenerID);
}
/**
* {@link ClearingMemberCategoryService#clearingMemberCategoryDelete(BaseRequest)}<br>
* Тест проверяет удаление сущности {@link ClearingMemberCategory} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link CommonDeleteRequest}:<br>
* {@link CommonDeleteRequest#id} - Идентификатор записи<br>
*/
@Test
void clearingMemberCategoryDelete() throws InterruptedException {
//ARRANGE
ClearingMemberCategory existsСlearingMemberCategory = new ClearingMemberCategory();
existsСlearingMemberCategory.setId(ID);
existsСlearingMemberCategory.setClearingMemberCategory("0000");
CommonDeleteRequest memberCategoryDeleteRequest = new CommonDeleteRequest();
memberCategoryDeleteRequest.setId(ID);
BaseRequest<CommonDeleteRequest> baseDeleteRequest = new BaseRequest<>();
baseDeleteRequest.setRequestPayload(memberCategoryDeleteRequest);
baseDeleteRequest.setId(ID);
baseDeleteRequest.setActionType(ActionType.DELETE);
String jsonBaseForDeleteRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseForDeleteRequest = objectMapper.writeValueAsString(baseDeleteRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
//ACT
//service set up
ClearingMemberCategoryService clearingMemberCategoryService = new ClearingMemberCategoryService(mockConsumer, hazelcastServiceTest);
//callbacks set up
clearingMemberCategoryService.afterPropertiesSet();
IMap<Long, ClearingMemberCategory> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_ClearingMemberCategory);
iMap.put(ID, existsСlearingMemberCategory);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_MEMBER_CATEGORY_DELETE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_MEMBER_CATEGORY_DELETE, PARTITION, 0, "key", jsonBaseForDeleteRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpDeleting = new TopicPartition(TOPIC_MEMBER_CATEGORY_DELETE, PARTITION);
startOffsetsUpdating.put(tpDeleting, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//waiting for hazelcast map item removes
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryRemovedListener<Long, Contact>) entryEvent -> {
System.out.println("Checking If removed..");
try {
waiter.wait(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (waiter) {
waiter.notify();
}
}, false);
synchronized (waiter) {
waiter.wait(100);
}
//ASSERT
Assertions.assertEquals(0, iMap.size());
//preparing hazelcastImdgProvider for next test
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,176 @@
package ru.spcex.clearing.company.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryUpdatedListener;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.TopicPartition;
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.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.profile.CompanyInfo;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.company.utils.MatcherFactory;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
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.domain.cud.company.CompanyInfoUpdateRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.util.Collections;
import java.util.HashMap;
import static ru.spcex.clearing.company.utils.MatcherFactory.usingIgnoringFieldsComparator;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
class CompanyInfoServiceTest {
public static final MatcherFactory.Matcher<CompanyInfo> COMPANY_INFO_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_COMPANY_INFO_UPDATE = Consts.DESTINATION_COMPANY_INFO_UPDATE;
private static final Long ID = 0L;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
/**
* {@link CompanyInfoService#companyInfoUpdate(BaseRequest)}<br>
* Тест проверяет обновление сущности {@link CompanyInfo} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link CompanyInfoUpdateRequest}:<br>
* {@link CompanyInfoUpdateRequest#id} - Идентификатор записи<br>
* {@link CompanyInfoUpdateRequest#corporationSoleType} - 1234<br>
* {@link CompanyInfoUpdateRequest#countryCode} - 1234<br>
* {@link CompanyInfoUpdateRequest#description} - updated description<br>
* {@link CompanyInfoUpdateRequest#professionalSign} - 1234<br>
* {@link CompanyInfoUpdateRequest#legalKind} - 1234<br>
* {@link CompanyInfoUpdateRequest#organizationType} - 1234<br>
* {@link CompanyInfoUpdateRequest#residence} - 1234<br>
* {@link CompanyInfoUpdateRequest#shortNameEng} - updated shortNameEng<br>
* {@link CompanyInfoUpdateRequest#fullNameEng} - updated fullNameEng<br>
* {@link CompanyInfoUpdateRequest#shortName} - updated shortName<br>
* {@link CompanyInfoUpdateRequest#fullName} - updated fullName<br>
*/
@Test
void companyInfoUpdate() throws InterruptedException {
//ARRANGE
CompanyInfo existsCompanyInfo = new CompanyInfo();
existsCompanyInfo.setId(ID);
existsCompanyInfo.setCompanyId(ID);
existsCompanyInfo.setCorporationSoleType("0000");
existsCompanyInfo.setCountryCode("0000");
existsCompanyInfo.setDescription("exists description");
existsCompanyInfo.setProfessionalSign("0000");
existsCompanyInfo.setLegalKind("0000");
existsCompanyInfo.setOrganizationType("0000");
existsCompanyInfo.setResidence("0000");
existsCompanyInfo.setShortNameEng("exists shortNameEng");
existsCompanyInfo.setFullNameEng("exists fullNameEng");
existsCompanyInfo.setShortName("exists shortName");
existsCompanyInfo.setFullName("exists fullName");
CompanyInfoUpdateRequest companyInfoUpdateRequest = new CompanyInfoUpdateRequest();
companyInfoUpdateRequest.setId(ID);
companyInfoUpdateRequest.setCorporationSoleType("1234");
companyInfoUpdateRequest.setCountryCode("1234");
companyInfoUpdateRequest.setDescription("updated description");
companyInfoUpdateRequest.setProfessionalSign("1234");
companyInfoUpdateRequest.setLegalKind("1234");
companyInfoUpdateRequest.setOrganizationType("1234");
companyInfoUpdateRequest.setResidence("1234");
companyInfoUpdateRequest.setShortNameEng("updated shortNameEng");
companyInfoUpdateRequest.setFullNameEng("updated fullNameEng");
companyInfoUpdateRequest.setShortName("updated shortName");
companyInfoUpdateRequest.setFullName("updated fullName");
BaseRequest<CompanyInfoUpdateRequest> baseUpdateRequest = new BaseRequest<>();
baseUpdateRequest.setRequestPayload(companyInfoUpdateRequest);
baseUpdateRequest.setId(ID);
baseUpdateRequest.setActionType(ActionType.UPDATE);
String jsonBaseForUpdatingRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseForUpdatingRequest = objectMapper.writeValueAsString(baseUpdateRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
CompanyInfo predictableCompanyInfo = new CompanyInfo();
predictableCompanyInfo.setId(ID);
predictableCompanyInfo.setCompanyId(ID);
predictableCompanyInfo.setCorporationSoleType("1234");
predictableCompanyInfo.setCountryCode("1234");
predictableCompanyInfo.setDescription("updated description");
predictableCompanyInfo.setProfessionalSign("1234");
predictableCompanyInfo.setLegalKind("1234");
predictableCompanyInfo.setOrganizationType("1234");
predictableCompanyInfo.setResidence("1234");
predictableCompanyInfo.setShortNameEng("updated shortNameEng");
predictableCompanyInfo.setFullNameEng("updated fullNameEng");
predictableCompanyInfo.setShortName("updated shortName");
predictableCompanyInfo.setFullName("updated fullName");
//ACT
//service set up
CompanyInfoService clearingMemberCategoryService = new CompanyInfoService(mockConsumer, hazelcastServiceTest);
//callbacks set up
clearingMemberCategoryService.afterPropertiesSet();
IMap<Long, CompanyInfo> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_Company);
iMap.put(ID, existsCompanyInfo);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_COMPANY_INFO_UPDATE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_COMPANY_INFO_UPDATE, PARTITION, 0, "key", jsonBaseForUpdatingRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpUpdating = new TopicPartition(TOPIC_COMPANY_INFO_UPDATE, PARTITION);
startOffsetsUpdating.put(tpUpdating, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//waiting for hazelcast map updates
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryUpdatedListener<Long, Contact>) entryEvent -> {
System.out.println("Checking If removed..");
try {
waiter.wait(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (waiter) {
waiter.notify();
}
}, false);
synchronized (waiter) {
waiter.wait(100);
}
//ASSERT
CompanyInfo resultUpdating = iMap.get(ID);
COMPANY_INFO_MATCHER.assertMatch(resultUpdating, predictableCompanyInfo);
//preparing hazelcastImdgProvider for next test
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,128 @@
package ru.spcex.clearing.company.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryRemovedListener;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.TopicPartition;
import org.junit.jupiter.api.Assertions;
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.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.company.utils.MatcherFactory;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
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.domain.cud.common.CommonDeleteRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.util.Collections;
import java.util.HashMap;
import static ru.spcex.clearing.company.utils.MatcherFactory.usingIgnoringFieldsComparator;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
class CompanyServiceTest {
public static final MatcherFactory.Matcher<ClearingMemberCategory> COMPANY_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_COMPANY_DELETE = Consts.DESTINATION_COMPANY_DELETE;
private static final Long ID = 0L;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
/**
* {@link CompanyService#deleteCompany(BaseRequest)}<br>
* Тест проверяет удаление сущности {@link Company} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link CommonDeleteRequest}:<br>
* {@link CommonDeleteRequest#id} - Идентификатор записи<br>
*/
@Test
void deleteCompany() throws InterruptedException {
//ARRANGE
Company existsCompany = new Company();
existsCompany.setId(ID);
CommonDeleteRequest memberCategoryDeleteRequest = new CommonDeleteRequest();
memberCategoryDeleteRequest.setId(ID);
BaseRequest<CommonDeleteRequest> baseDeleteRequest = new BaseRequest<>();
baseDeleteRequest.setRequestPayload(memberCategoryDeleteRequest);
baseDeleteRequest.setId(ID);
baseDeleteRequest.setActionType(ActionType.DELETE);
String jsonBaseForDeleteRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseForDeleteRequest = objectMapper.writeValueAsString(baseDeleteRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
//ACT
//service set up
CompanyService companyService = new CompanyService(mockConsumer, hazelcastServiceTest);
//callbacks set up
companyService.afterPropertiesSet();
IMap<Long, Company> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_Company);
iMap.put(ID, existsCompany);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_COMPANY_DELETE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_COMPANY_DELETE, PARTITION, 0, "key", jsonBaseForDeleteRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpDeleting = new TopicPartition(TOPIC_COMPANY_DELETE, PARTITION);
startOffsetsUpdating.put(tpDeleting, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//waiting for hazelcast map item removes
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryRemovedListener<Long, Contact>) entryEvent -> {
System.out.println("Checking If removed..");
try {
waiter.wait(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (waiter) {
waiter.notify();
}
}, false);
synchronized (waiter) {
waiter.wait(100);
}
//ASSERT
Assertions.assertEquals(0, iMap.size());
//preparing hazelcastImdgProvider for next test
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,142 @@
package ru.spcex.clearing.company.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryUpdatedListener;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.TopicPartition;
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.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.company.CompanySymbols;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.company.utils.MatcherFactory;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
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.domain.cud.company.CompanySymbolUpdateRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.util.Collections;
import java.util.HashMap;
import static ru.spcex.clearing.company.utils.MatcherFactory.usingIgnoringFieldsComparator;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
class CompanySymbolServiceTest {
public static final MatcherFactory.Matcher<CompanySymbols> COMPANY_SYMBOL_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_COMPANY_SYMBOL_UPDATE = Consts.DESTINATION_COMPANY_SYMBOL_UPDATE;
private static final Long ID = 0L;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
/**
* {@link CompanySymbolService#companySymbolUpdate(BaseRequest)}<br>
* Тест проверяет обновление сущности {@link CompanySymbols} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link CompanySymbolUpdateRequest}:<br>
* {@link CompanySymbolUpdateRequest#id} - Идентификатор записи<br>
* {@link CompanySymbolUpdateRequest#companyId} - Идентификатор записи<br>
* {@link CompanySymbolUpdateRequest#companySymbol} - 1234<br>
* {@link CompanySymbolUpdateRequest#companySymbolValue} - new companySymbolValue<br>
*/
@Test
void companySymbolUpdate() throws InterruptedException {
//ARRANGE
CompanySymbols existsCompanySymbols = new CompanySymbols();
existsCompanySymbols.setId(ID);
existsCompanySymbols.setCompanyId(ID);
existsCompanySymbols.setCompanySymbol("0000");
existsCompanySymbols.setCompanySymbolValue("exists companySymbolValue");
CompanySymbolUpdateRequest companySymbolUpdateRequest = new CompanySymbolUpdateRequest();
companySymbolUpdateRequest.setId(ID);
companySymbolUpdateRequest.setCompanyId(ID);
companySymbolUpdateRequest.setCompanySymbol("1234");
companySymbolUpdateRequest.setCompanySymbolValue("new companySymbolValue");
BaseRequest<CompanySymbolUpdateRequest> baseUpdateRequest = new BaseRequest<>();
baseUpdateRequest.setRequestPayload(companySymbolUpdateRequest);
baseUpdateRequest.setId(ID);
baseUpdateRequest.setActionType(ActionType.UPDATE);
String jsonBaseForUpdatingRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseForUpdatingRequest = objectMapper.writeValueAsString(baseUpdateRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
CompanySymbols predictableCompanySymbols = new CompanySymbols();
predictableCompanySymbols.setId(ID);
predictableCompanySymbols.setCompanyId(ID);
predictableCompanySymbols.setCompanySymbol("0000");
predictableCompanySymbols.setCompanySymbolValue("new companySymbolValue");
//ACT
//service set up
CompanySymbolService companySymbolService = new CompanySymbolService(mockConsumer, hazelcastServiceTest);
//callbacks set up
companySymbolService.afterPropertiesSet();
IMap<Long, CompanySymbols> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_CompanySymbols);
iMap.put(ID, existsCompanySymbols);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_COMPANY_SYMBOL_UPDATE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_COMPANY_SYMBOL_UPDATE, PARTITION, 0, "key", jsonBaseForUpdatingRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpUpdating = new TopicPartition(TOPIC_COMPANY_SYMBOL_UPDATE, PARTITION);
startOffsetsUpdating.put(tpUpdating, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//waiting for hazelcast map item updates
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryUpdatedListener<Long, Contact>) entryEvent -> {
System.out.println("Checking If removed..");
try {
waiter.wait(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (waiter) {
waiter.notify();
}
}, false);
synchronized (waiter) {
waiter.wait(100);
}
//ASSERT
CompanySymbols resultUpdating = iMap.get(ID);
COMPANY_SYMBOL_MATCHER.assertMatch(resultUpdating, predictableCompanySymbols);
//preparing hazelcastImdgProvider for next test
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,140 @@
package ru.spcex.clearing.company.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryUpdatedListener;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.MockConsumer;
import org.apache.kafka.clients.consumer.OffsetResetStrategy;
import org.apache.kafka.common.TopicPartition;
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.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.company.utils.MatcherFactory;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
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.domain.cud.company.ContactUpdateRequest;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.util.Collections;
import java.util.HashMap;
import static ru.spcex.clearing.company.utils.MatcherFactory.usingIgnoringFieldsComparator;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
class ContactServiceTest {
public static final MatcherFactory.Matcher<Contact> CONTACT_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_CONTACT_UPDATE = Consts.DESTINATION_CONTACT_UPDATE;
private static final Long ID = 0L;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
private MockConsumer<String, Object> mockConsumer;
@BeforeEach
void setUp() {
mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
}
/**
* {@link ContactService#contactUpdate(BaseRequest)}<br>
* Тест проверяет обновление сущности {@link Contact} в Hazelcast при передаче из Apache Kafka.<br>
* Входной запрос {@link ContactUpdateRequest}:<br>
* {@link ContactUpdateRequest#id} - Идентификатор записи<br>
* {@link ContactUpdateRequest#companyId} - Идентификатор записи<br>
* {@link ContactUpdateRequest#contactType} - 1234<br>
* {@link ContactUpdateRequest#contactValue} - new ContactValue<br>
*/
@Test
void contactUpdate() throws InterruptedException {
//ARRANGE
Contact existsContact = new Contact();
existsContact.setId(ID);
existsContact.setCompanyId(ID);
existsContact.setContactType("0000");
existsContact.setContactValue("exists ContactValue");
ContactUpdateRequest contactUpdateRequest = new ContactUpdateRequest();
contactUpdateRequest.setId(ID);
contactUpdateRequest.setCompanyId(1L);
contactUpdateRequest.setContactType("1234");
contactUpdateRequest.setContactValue("new ContactValue");
BaseRequest<ContactUpdateRequest> baseUpdateRequest = new BaseRequest<>();
baseUpdateRequest.setRequestPayload(contactUpdateRequest);
baseUpdateRequest.setId(ID);
baseUpdateRequest.setActionType(ActionType.UPDATE);
String jsonBaseForUpdatingRequest;
ObjectMapper objectMapper = new ObjectMapper();
try {
jsonBaseForUpdatingRequest = objectMapper.writeValueAsString(baseUpdateRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
Contact predictableContact = new Contact();
predictableContact.setId(ID);
predictableContact.setCompanyId(ID);
predictableContact.setContactType("0000");
predictableContact.setContactValue("new ContactValue");
//ACT
//service set up
ContactService contactService = new ContactService(mockConsumer, hazelcastServiceTest);
contactService.afterPropertiesSet();
//callbacks set up
IMap<Long, Contact> iMap = hazelcastServiceTest.getHazelcast().getMap(IMDGDistributedNames.Map_Contact);
iMap.put(ID, existsContact);
//KAFKA
mockConsumer.schedulePollTask(() -> {
mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC_CONTACT_UPDATE, PARTITION)));
mockConsumer.addRecord(new ConsumerRecord<>(TOPIC_CONTACT_UPDATE, PARTITION, 0, "key", jsonBaseForUpdatingRequest));
});
HashMap<TopicPartition, Long> startOffsetsUpdating = new HashMap<>();
TopicPartition tpUpdating = new TopicPartition(TOPIC_CONTACT_UPDATE, PARTITION);
startOffsetsUpdating.put(tpUpdating, 0L);
mockConsumer.updateBeginningOffsets(startOffsetsUpdating);
//waiting for hazelcast map updates
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryUpdatedListener<Long, Contact>) entryEvent -> {
System.out.println("Checking If removed..");
try {
waiter.wait(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (waiter) {
waiter.notify();
}
}, false);
synchronized (waiter) {
waiter.wait(100);
}
//ASSERT
Contact resultUpdating = iMap.get(ID);
CONTACT_MATCHER.assertMatch(resultUpdating, predictableContact);
//preparing hazelcastImdgProvider for next test
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,38 @@
package ru.spcex.clearing.company.utils;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Factory for creating test matchers.
* <p>
* Comparing actual and expected objects via AssertJ
*/
public class MatcherFactory {
public static <T> Matcher<T> usingIgnoringFieldsComparator(String... fieldsToIgnore) {
return new Matcher<>(fieldsToIgnore);
}
public static class Matcher<T> {
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<T> actual, T... expected) {
assertMatch(actual, Arrays.asList(expected));
}
public void assertMatch(Iterable<T> actual, Iterable<T> expected) {
assertThat(actual).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(expected);
}
}
}