Merge remote-tracking branch 'origin/psemenkov' into dev

# Conflicts:
#	clearing-parent/backend-api/pom.xml
This commit is contained in:
etreshenkov 2022-10-27 16:37:15 +03:00
commit 4390380893
18 changed files with 762 additions and 20 deletions

View file

@ -37,7 +37,7 @@ import static ru.spcex.clearing.account.utils.MatcherFactory.usingIgnoringFields
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class})
public class BankAccountServiceTest {
public static final Matcher<BankAccount> BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator("id");
public static final Matcher<BankAccount> BANK_ACCOUNT_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_ACCOUNT_NEW = Consts.DESTINATION_BANK_ACCOUNT_NEW;
private static final String TOPIC_ACCOUNT_UPDATE = Consts.DESTINATION_BANK_ACCOUNT_UPDATE;

View file

@ -61,6 +61,27 @@
<groupId>ru.spcex.platform</groupId>
<artifactId>platform-enum</artifactId>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<scope>test</scope>
</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>
<dependencyManagement>
@ -156,6 +177,24 @@
</execution>
</executions>
</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>
</project>

View file

@ -0,0 +1,54 @@
package ru.spcex.clearing.backendapi.controller.queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import ru.spcex.clearing.backendapi.config.WebConfig;
import ru.spcex.clearing.backendapi.controller.queue.company.DeleteCompanyController;
import ru.spcex.clearing.backendapi.controller.queue.config.*;
import javax.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicLong;
@SpringJUnitWebConfig(classes = {
WebConfig.class,
IOperator.class,
StateLoaderImplConfig.class,
DeleteCompanyController.class,
BankAccountControllerConfig.class,
KafkaConfig.class,
HazelcastServiceTestConfiguration.class,
Jackson2HttpConverterConfig.class})
public abstract class AbstractControllerTest {
protected static final AtomicLong currentId = new AtomicLong();
private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter();
static {
CHARACTER_ENCODING_FILTER.setEncoding("UTF-8");
CHARACTER_ENCODING_FILTER.setForceEncoding(true);
}
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@PostConstruct
private void postConstruct() {
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.addFilter(CHARACTER_ENCODING_FILTER)
// .apply(springSecurity())
.build();
}
protected ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception {
return mockMvc.perform(builder);
}
}

View file

@ -0,0 +1,245 @@
package ru.spcex.clearing.backendapi.controller.queue.account;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import ru.spcex.clearing.backendapi.config.WebConfig;
import ru.spcex.clearing.backendapi.controller.queue.config.*;
import ru.spcex.clearing.backendapi.controller.queue.utils.MatcherFactory;
import ru.spcex.clearing.backendapi.controller.request.cud.account.BankAccountNewAction;
import ru.spcex.clearing.backendapi.controller.request.cud.account.BankAccountUpdateAction;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.QueueSuccessResponse;
import ru.spcex.clearing.backendapi.domain.actions.IAction;
import ru.spcex.clearing.backendapi.errors.ActionValidationException;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import ru.spcex.clearing.platform.messaging.domain.cud.account.BankAccountNewRequest;
import javax.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static ru.spcex.clearing.backendapi.controller.queue.utils.JsonUtil.writeValue;
@SpringJUnitWebConfig(classes = {
WebConfig.class,
IOperator.class,
BankAccountControllerConfig.class,
KafkaConfig.class,
HazelcastServiceTestConfiguration.class,
Jackson2HttpConverterConfig.class})
class BankAccountControllerTest {
public static final MatcherFactory.Matcher<CudResponse> CUD_RESPONSE_MATCHER = MatcherFactory.usingIgnoringFieldsComparator(CudResponse.class);
private static final String REST_URL = "/securities/bank-accounts/";
private static final CharacterEncodingFilter CHARACTER_ENCODING_FILTER = new CharacterEncodingFilter();
private static final AtomicLong currentId = new AtomicLong();
static {
CHARACTER_ENCODING_FILTER.setEncoding("UTF-8");
CHARACTER_ENCODING_FILTER.setForceEncoding(true);
}
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@PostConstruct
private void postConstruct() {
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.addFilter(CHARACTER_ENCODING_FILTER)
// .apply(springSecurity())
.build();
}
/**
* {@link BankAccountController#add(BankAccountNewAction)}<br>
* Тест проверяет получение сущности {@link BankAccountNewAction} по REST API и отправку в Apache Kafka.<br>
* Входной запрос {@link BankAccountNewRequest}:<br>
* {@link BankAccountNewRequest#bankIdentificationCode} - 044525776<br>
* {@link BankAccountNewRequest#bankName} - Beta Money Bank<br>
* {@link BankAccountNewRequest#correspondentAccount} - 30101111111111111776<br>
* {@link BankAccountNewRequest#correspondentAccountName} - correspondent<br>
* {@link BankAccountNewRequest#currency} - RUB<br>
* {@link BankAccountNewRequest#destination} - destination<br>
* {@link BankAccountNewRequest#taxpayerIdentificationNumber} - 3664011397<br>
* {@link BankAccountNewRequest#taxRegistrationReasonCode} - 01<br>
* {@link BankAccountNewRequest#account} - 11111222223333344444<br>
*/
@Test
void add() throws Exception {
//ARRANGE
BankAccountNewAction bankAccountNewAction = getBankAccountNewAction(
"044525776",
"Beta Money Bank",
"30101111111111111776",
"correspondent",
"RUB",
"destination",
"3664011397",
"01",
"11111222223333344444");
CudResponse extended = new CudResponse();
extended.setCode(0L);
extended.setMessage("success");
extended.setPayload(new QueueSuccessResponse(ActionType.NEW, currentId.getAndIncrement()));
//ACT
mockMvc.perform(MockMvcRequestBuilders.post(REST_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(writeValue(bankAccountNewAction)))
.andDo(print())//output to the log request and response
// ASSERT
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(content().json(writeValue(extended)));
}
/**
* {@link BankAccountController#add(BankAccountNewAction)}<br>
* Тест проверяет работу валидации сущности {@link BankAccountNewAction} принятой по REST API для отправку в Apache Kafka.<br>
* Входной запрос {@link BankAccountNewRequest}:<br>
* {@link BankAccountNewRequest#bankIdentificationCode} - 044525776 или ""<br>
* {@link BankAccountNewRequest#bankName} - Beta Money Bank или ""<br>
* {@link BankAccountNewRequest#correspondentAccount} - 30101111111111111776 или ""<br>
* {@link BankAccountNewRequest#correspondentAccountName} - correspondent или ""<br>
* {@link BankAccountNewRequest#currency} - RUB или ""<br>
* {@link BankAccountNewRequest#destination} - destinatio или ""n<br>
* {@link BankAccountNewRequest#taxpayerIdentificationNumber} - 3664011397 или ""<br>
* {@link BankAccountNewRequest#taxRegistrationReasonCode} - 01 или ""<br>
* {@link BankAccountNewRequest#account} - 11111222223333344444 или ""<br>
*/
@Test
void addWithException() {
assertThrowsFor(getBankAccountNewAction("", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "", "correspondent", "RUB", "destination", "3664011397", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "", "RUB", "destination", "3664011397", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "", "destination", "3664011397", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "", "3664011397", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "", "01", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "", "11111222223333344444"));
assertThrowsFor(getBankAccountNewAction("044525776", "Beta Money Bank", "30101111111111111776", "correspondent", "RUB", "destination", "3664011397", "01", ""));
}
/**
* {@link BankAccountController#update(Long, BankAccountUpdateAction)}<br>
* Тест проверяет получение сущности {@link BankAccountUpdateAction} по REST API и отправку в Apache Kafka.<br>
* Входной запрос {@link BankAccountUpdateAction}:<br>
* {@link BankAccountUpdateAction#bankIdentificationCode} - 044525776<br>
* {@link BankAccountUpdateAction#bankName} - Beta Money Bank<br>
* {@link BankAccountUpdateAction#correspondentAccount} - 30101111111111111776<br>
* {@link BankAccountUpdateAction#correspondentAccountName} - correspondent<br>
* {@link BankAccountUpdateAction#currency} - RUB<br>
* {@link BankAccountUpdateAction#destination} - destination<br>
* {@link BankAccountUpdateAction#taxpayerIdentificationNumber} - 3664011397<br>
* {@link BankAccountUpdateAction#taxRegistrationReasonCode} - 01<br>
* {@link BankAccountUpdateAction#account} - 11111222223333344444<br>
*/
@Test
void update() throws Exception {
//ARRANGE
BankAccountUpdateAction bankAccountNewAction = getBankAccountUpdateAction(
"044525776",
"Beta Money Bank",
"30101111111111111776",
"correspondent",
"RUB",
"destination",
"3664011397",
"01",
"11111222223333344444");
CudResponse extended = new CudResponse();
extended.setCode(0L);
extended.setMessage("success");
extended.setPayload(new QueueSuccessResponse(ActionType.UPDATE, currentId.getAndIncrement()));
//ACT
mockMvc.perform(MockMvcRequestBuilders.put(REST_URL + "0")
.contentType(MediaType.APPLICATION_JSON)
.content(writeValue(bankAccountNewAction)))
.andDo(print())//output to the log request and response
// ASSERT
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(content().json(writeValue(extended)));
}
/**
* {@link BankAccountController#delete(Long)} <br>
* Тест проверяет получение id сущности {@link Long} по REST API и отправку в Apache Kafka.<br>
* Входной запрос {@link Long}: - 0L<br>
*/
@Test
void delete() throws Exception {
//ARRANGE
CudResponse extended = new CudResponse();
extended.setCode(0L);
extended.setMessage("success");
extended.setPayload(new QueueSuccessResponse(ActionType.DELETE, currentId.getAndIncrement()));
//ACT
mockMvc.perform(MockMvcRequestBuilders.delete(REST_URL + "0")
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())//output to the log request and response
// ASSERT
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(content().json(writeValue(extended)));
}
private void assertThrowsFor(IAction<?> iAction) {
assertThrows(ActionValidationException.class, () -> {
try {
mockMvc.perform(MockMvcRequestBuilders.post(REST_URL).contentType(MediaType.APPLICATION_JSON).content(writeValue(iAction)));
} catch (Exception e) {
Throwable rootCause = NestedExceptionUtils.getRootCause(e);
throw rootCause != null ? rootCause : e;
}
});
}
private BankAccountNewAction getBankAccountNewAction(String BankIdentificationCode, String BankName, String CorrespondentAccount, String CorrespondentAccountName,
String Currency, String Destination, String TaxpayerIdentificationNumber, String TaxRegistrationReasonCode,
String Account) {
BankAccountNewAction bankAccountNewAction = new BankAccountNewAction();
bankAccountNewAction.setBankIdentificationCode(BankIdentificationCode);
bankAccountNewAction.setBankName(BankName);
bankAccountNewAction.setCorrespondentAccount(CorrespondentAccount);
bankAccountNewAction.setCorrespondentAccountName(CorrespondentAccountName);
bankAccountNewAction.setCurrency(Currency);
bankAccountNewAction.setDestination(Destination);
bankAccountNewAction.setTaxpayerIdentificationNumber(TaxpayerIdentificationNumber);
bankAccountNewAction.setTaxRegistrationReasonCode(TaxRegistrationReasonCode);
bankAccountNewAction.setAccount(Account);
return bankAccountNewAction;
}
private BankAccountUpdateAction getBankAccountUpdateAction(String BankIdentificationCode, String BankName, String CorrespondentAccount, String CorrespondentAccountName,
String Currency, String Destination, String TaxpayerIdentificationNumber, String TaxRegistrationReasonCode,
String Account) {
BankAccountUpdateAction bankAccountUpdateAction = new BankAccountUpdateAction();
bankAccountUpdateAction.setBankIdentificationCode(BankIdentificationCode);
bankAccountUpdateAction.setBankName(BankName);
bankAccountUpdateAction.setCorrespondentAccount(CorrespondentAccount);
bankAccountUpdateAction.setCorrespondentAccountName(CorrespondentAccountName);
bankAccountUpdateAction.setCurrency(Currency);
bankAccountUpdateAction.setDestination(Destination);
bankAccountUpdateAction.setTaxpayerIdentificationNumber(TaxpayerIdentificationNumber);
bankAccountUpdateAction.setTaxRegistrationReasonCode(TaxRegistrationReasonCode);
bankAccountUpdateAction.setAccount(Account);
return bankAccountUpdateAction;
}
}

View file

@ -0,0 +1,40 @@
package ru.spcex.clearing.backendapi.controller.queue.company;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import ru.spcex.clearing.backendapi.controller.queue.AbstractControllerTest;
import ru.spcex.clearing.backendapi.controller.response.cud.CudResponse;
import ru.spcex.clearing.backendapi.controller.response.cud.QueueSuccessResponse;
import ru.spcex.clearing.platform.messaging.domain.ActionType;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static ru.spcex.clearing.backendapi.controller.queue.utils.JsonUtil.writeValue;
class DeleteCompanyControllerTest extends AbstractControllerTest {
private static final String REST_URL = "/companies/";
/**
* {@link DeleteCompanyController#delete(Long)} <br>
* Тест проверяет получение id сущности {@link Long} по REST API и отправку в Apache Kafka.<br>
* Входной запрос {@link Long}: - 0L<br>
*/
@Test
void delete() throws Exception {
//ARRANGE
CudResponse extended = new CudResponse();
extended.setCode(0L);
extended.setMessage("success");
extended.setPayload(new QueueSuccessResponse(ActionType.DELETE, currentId.getAndIncrement()));
//ACT
perform(MockMvcRequestBuilders.delete(REST_URL + "0")
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())//output to the log request and response
// ASSERT
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(content().json(writeValue(extended)));
}
}

View file

@ -0,0 +1,28 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.backendapi.controller.queue.account.BankAccountController;
import ru.spcex.clearing.backendapi.service.IOperator;
import ru.spcex.clearing.backendapi.service.impl.StateLoaderImpl;
@Configuration
public class BankAccountControllerConfig {
@Autowired
@Qualifier("iOperator")
private IOperator operator;
@Autowired
@Qualifier("stateLoaderImpl")
private StateLoaderImpl stateLoader;
@Bean
public BankAccountController createBankAccountController() {
return new BankAccountController(operator, stateLoader);
}
}

View file

@ -0,0 +1,25 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.backendapi.controller.queue.company.DeleteCompanyController;
import ru.spcex.clearing.backendapi.service.IOperator;
import ru.spcex.clearing.backendapi.service.impl.StateLoaderImpl;
@Configuration
public class DeleteCompanyControllerConfig {
@Autowired
@Qualifier("iOperator")
private IOperator operator;
@Autowired
@Qualifier("stateLoaderImpl")
private StateLoaderImpl stateLoader;
@Bean
public DeleteCompanyController createDeleteCompanyController() {
return new DeleteCompanyController(operator, stateLoader);
}
}

View file

@ -0,0 +1,68 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import com.hazelcast.config.*;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import ru.spcex.platform.imdg.iml.hazelcast.config.HazelcastClientParams;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import ru.spcex.platform.imdg.iml.hazelcast.util.HazelcastHelper;
import java.util.List;
import java.util.Random;
@Configuration
public class HazelcastServiceTestConfiguration {
private HazelcastInstance hazelcastInstance;
private static ThreadPoolTaskExecutor createThreadPoolTaskExecutor(int maxPoolSz, boolean waitForCompletion) {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
if (maxPoolSz > 2) {
pool.setKeepAliveSeconds(60);
pool.setAllowCoreThreadTimeOut(true);
}
pool.setCorePoolSize(maxPoolSz);
pool.setWaitForTasksToCompleteOnShutdown(waitForCompletion);
return pool;
}
@Bean(name = "hazelcastServiceTest")
public HazelcastService hazelcastService(@Qualifier("taskExecutorHazelcastClientInitializer") ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer, @Qualifier("taskExecutorIdGeneratorAwaiter") ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter, HazelcastClientParams params) {
Config cfg = new Config();
cfg.setInstanceName("localhost");
NetworkConfig networkConfig = new NetworkConfig();
JoinConfig joinConfig = new JoinConfig();
joinConfig.setMulticastConfig(new MulticastConfig().setEnabled(false));
joinConfig.setTcpIpConfig(new TcpIpConfig().setEnabled(true).setMembers(List.of("127.0.0.1")));
networkConfig.setJoin(joinConfig);
cfg.setNetworkConfig(networkConfig);
hazelcastInstance = Hazelcast.newHazelcastInstance(cfg);
HazelcastHelper.otcSystem_setStorageState(true, hazelcastInstance);
return new HazelcastService(taskExecutorHazelcastClientInitializer, taskExecutorIdGeneratorAwaiter, params);
}
@Bean(name = "taskExecutorHazelcastClientInitializer")
public ThreadPoolTaskExecutor taskExecutorHazelcastClientInitializer() {
return createThreadPoolTaskExecutor(1, true);
}
@Bean(name = "taskExecutorIdGeneratorAwaiter")
public ThreadPoolTaskExecutor taskExecutorIdGeneratorAwaiter() {
return createThreadPoolTaskExecutor(1, false);
}
@Bean(name = "hazelcastClientParams")
public HazelcastClientParams getHazelcastClientParams() {
HazelcastClientParams params = new HazelcastClientParams();
params.setLogin("dev");
params.setPassword("dev-pass");
params.setClusterMembers("127.0.0.1");
params.setInstanceName("hzTestClient" + new Random().nextInt());
params.setNearCacheConfig(new NearCacheConfig());
return params;
}
}

View file

@ -0,0 +1,24 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import org.apache.kafka.clients.producer.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.backendapi.service.impl.OperatorImpl;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
@Configuration
public class IOperator {
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
@Autowired
@Bean
public OperatorImpl createIOperator(Producer<String, Object> kafka) {
return new OperatorImpl(kafka, hazelcastServiceTest);
}
}

View file

@ -0,0 +1,41 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration
public class Jackson2HttpConverterConfig {
@Bean("customJsonHttpConverter")
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
return new MappingJackson2HttpMessageConverter(JacksonObjectMapper.getMapper());
}
public static class JacksonObjectMapper extends ObjectMapper {
private static final ObjectMapper MAPPER = new JacksonObjectMapper();
private JacksonObjectMapper() {
//настройки Ильи
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
//настройки какие были на курсе пока не нужны..
// модуль для корректной сериализации LocalDateTime в поля JSON - JavaTimeModule модуль библиотеки jackson-datatype-jsr310
// registerModule(new JavaTimeModule());
// configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// запрещаем доступ ко всем полям и методам класса и потом разрешаем доступ только к полям, нужны чтобы не было лишних полей из-за методов как: public ActionType getActionType() у BankAccountNewAction
setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
// не сериализуем null-поля
// setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
public static ObjectMapper getMapper() {
return MAPPER;
}
}
}

View file

@ -0,0 +1,18 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import org.apache.kafka.clients.producer.MockProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.platform.messaging.serialization.JsonSerializer;
@Configuration
public class KafkaConfig {
@Bean
public Producer<String, Object> createProducer() {
return new MockProducer<>(true, new StringSerializer(), new JsonSerializer());
}
}

View file

@ -0,0 +1,22 @@
package ru.spcex.clearing.backendapi.controller.queue.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.spcex.clearing.backendapi.service.impl.StateLoaderImpl;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
@Configuration
public class StateLoaderImplConfig {
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastServiceTest;
@Bean(name = "stateLoaderImpl")
public StateLoaderImpl createIOperator() {
return new StateLoaderImpl(hazelcastServiceTest);
}
}

View file

@ -0,0 +1,47 @@
package ru.spcex.clearing.backendapi.controller.queue.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static ru.spcex.clearing.backendapi.controller.queue.config.Jackson2HttpConverterConfig.JacksonObjectMapper.getMapper;
public class JsonUtil {
public static <T> List<T> readValues(String json, Class<T> clazz) {
ObjectReader reader = getMapper().readerFor(clazz);
try {
return reader.<T>readValues(json).readAll();
} catch (IOException e) {
throw new IllegalArgumentException("Invalid read array from JSON:\n'" + json + "'", e);
}
}
public static <T> T readValue(String json, Class<T> clazz) {
try {
return getMapper().readValue(json, clazz);
} catch (IOException e) {
throw new IllegalArgumentException("Invalid read from JSON:\n'" + json + "'", e);
}
}
public static <T> String writeValue(T obj) {
try {
return getMapper().writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new IllegalStateException("Invalid write to JSON:\n'" + obj + "'", e);
}
}
public static <T> String writeIgnoreProps(T obj, String... ignoreProps) {
Map<String, Object> map = getMapper().convertValue(obj, new TypeReference<>() {
});
map.keySet().removeAll(Set.of(ignoreProps));
return writeValue(map);
}
}

View file

@ -0,0 +1,82 @@
package ru.spcex.clearing.backendapi.controller.queue.utils;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.ResultMatcher;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.function.BiConsumer;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Factory for creating test matchers.
* <p>
* Comparing actual and expected objects via AssertJ
* Support converting json MvcResult to objects for comparation.
*/
public class MatcherFactory {
public static <T> Matcher<T> usingAssertions(Class<T> clazz, BiConsumer<T, T> assertion, BiConsumer<Iterable<T>, Iterable<T>> iterableAssertion) {
return new Matcher<>(clazz, assertion, iterableAssertion);
}
public static <T> Matcher<T> usingEqualsComparator(Class<T> clazz) {
return usingAssertions(clazz,
(a, e) -> assertThat(a).isEqualTo(e),
(a, e) -> assertThat(a).isEqualTo(e));
}
public static <T> Matcher<T> usingIgnoringFieldsComparator(Class<T> clazz, String... fieldsToIgnore) {
return usingAssertions(clazz,
(a, e) -> assertThat(a).usingRecursiveComparison().ignoringFields(fieldsToIgnore).isEqualTo(e),
(a, e) -> assertThat(a).usingRecursiveFieldByFieldElementComparatorIgnoringFields(fieldsToIgnore).isEqualTo(e));
}
public static class Matcher<T> {
private final Class<T> clazz;
private final BiConsumer<T, T> assertion;
private final BiConsumer<Iterable<T>, Iterable<T>> iterableAssertion;
private Matcher(Class<T> clazz, BiConsumer<T, T> assertion, BiConsumer<Iterable<T>, Iterable<T>> iterableAssertion) {
this.clazz = clazz;
this.assertion = assertion;
this.iterableAssertion = iterableAssertion;
}
private static String getContent(MvcResult result) throws UnsupportedEncodingException {
return result.getResponse().getContentAsString();
}
public void assertMatch(T actual, T expected) {
assertion.accept(actual, expected);
}
@SafeVarargs
public final void assertMatch(Iterable<T> actual, T... expected) {
assertMatch(actual, List.of(expected));
}
public void assertMatch(Iterable<T> actual, Iterable<T> expected) {
iterableAssertion.accept(actual, expected);
}
public ResultMatcher contentJson(T expected) {
return result -> assertMatch(JsonUtil.readValue(getContent(result), clazz), expected);
}
@SafeVarargs
public final ResultMatcher contentJson(T... expected) {
return contentJson(List.of(expected));
}
public ResultMatcher contentJson(Iterable<T> expected) {
return result -> assertMatch(JsonUtil.readValues(getContent(result), clazz), expected);
}
public T readFromJson(ResultActions action) throws UnsupportedEncodingException {
return JsonUtil.readValue(getContent(action.andReturn()), clazz);
}
}
}

View file

@ -9,7 +9,6 @@ import java.util.*;
/**
* MapStore для шаблонных бизнес-объектов
* @Component
*/
public abstract class TemplateMapStore<T extends SpcexObjectBase> extends ObjectBaseMapStore<T> implements AutoconfiguredMap<T> {
@ -22,13 +21,13 @@ public abstract class TemplateMapStore<T extends SpcexObjectBase> extends Object
}
/**
*
* @return IMDGDistributedNames.*
*/
public abstract String getMapName();
/**
* Список индексируемых полей, для быстрого поиска
*
* @return
*/
public String[] getIndexingField() {
@ -37,6 +36,7 @@ public abstract class TemplateMapStore<T extends SpcexObjectBase> extends Object
/**
* Десериализатор
*
* @param resultSet
* @return
*/
@ -51,6 +51,7 @@ public abstract class TemplateMapStore<T extends SpcexObjectBase> extends Object
/**
* Сериализатор
*
* @param resultSet
* @return Object[] args
*/

View file

@ -15,13 +15,11 @@ import java.time.Instant;
public abstract class AbstractUpdateMapService implements InitializingBean,
EntryAddedListener<Long, Object>, EntryUpdatedListener<Long, Object>, EntryRemovedListener<Long, Object> {
private final Logger log = LoggerFactory.getLogger(this.getClass());
protected final String EVENT_CREATE="CREATE";
protected final String EVENT_UPDATE="UPDATE";
protected final String EVENT_DELETE="DELETE";
protected final String EVENT_CREATE = "CREATE";
protected final String EVENT_UPDATE = "UPDATE";
protected final String EVENT_DELETE = "DELETE";
protected final HazelcastInstance hazelcastServerInstance;
private final Logger log = LoggerFactory.getLogger(this.getClass());
public AbstractUpdateMapService(HazelcastInstance hazelcastServerInstance) {
this.hazelcastServerInstance = hazelcastServerInstance;

View file

@ -4,11 +4,7 @@ import java.io.Serializable;
import java.util.Objects;
public interface IEnumId extends Serializable {
Long getId();
default boolean equalsById(Long id) {
return id != null && getId().equals(id);
}
Long UNDEFINED_VALUE = Long.MIN_VALUE;
/**
* Проверяет что среди данного набора Enum, присутствует элемент с данным id
@ -46,7 +42,7 @@ public interface IEnumId extends Serializable {
* Возвращает Enum по id, если в заданном классе такой определен
* id может быть null
*
* @return Enum если нашел, иначе <tt>null</tt>
* @return Enum если нашел, иначе null
*/
static <T extends Enum<T> & IEnumId> T getEnumById(Class<T> enumClass, Long id) {
for (T e : enumClass.getEnumConstants()) {
@ -60,5 +56,9 @@ public interface IEnumId extends Serializable {
return enumVal == null ? null : enumVal.getId();
}
Long UNDEFINED_VALUE = Long.MIN_VALUE;
Long getId();
default boolean equalsById(Long id) {
return id != null && getId().equals(id);
}
}

18
pom.xml
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">
<modelVersion>4.0.0</modelVersion>
@ -30,8 +30,10 @@
<!--suppress UnresolvedMavenProperty -->
<folder_root_clearing>${folder_root_clearing_temp}</folder_root_clearing>
<folder_root_clearing_backend-api>${folder_root_clearing}/clearing-parent/backend-api</folder_root_clearing_backend-api>
<folder_root_clearing_securities-service>${folder_root_clearing}/clearing-parent/securities-service</folder_root_clearing_securities-service>
<folder_root_clearing_backend-api>${folder_root_clearing}/clearing-parent/backend-api
</folder_root_clearing_backend-api>
<folder_root_clearing_securities-service>${folder_root_clearing}/clearing-parent/securities-service
</folder_root_clearing_securities-service>
<folder_root_clearing_imdg>${folder_root_clearing}/clearing-parent/imdg</folder_root_clearing_imdg>
<folder_root_dbf-exporter>${folder_root_clearing}/clearing-parent/dbf-exporter</folder_root_dbf-exporter>
<folder_root_dbf-importer>${folder_root_clearing}/clearing-parent/dbf-importer</folder_root_dbf-importer>
@ -290,6 +292,14 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
</plugins>
</build>
</project>