---
Тест на KeyRateService

http://git.mfd.msk/mfd/clearing/issues/5
---
Тест на MoneyMarketSecurityService
This commit is contained in:
mivanov 2022-09-16 17:40:28 +03:00
parent 2b8ee91f76
commit cc01789369
13 changed files with 1143 additions and 1 deletions

View file

@ -36,6 +36,46 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View file

@ -0,0 +1,16 @@
package ru.spcex.clearing.securities.config;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HazelcastInstanceTestConfiguration {
@Bean(name = "hazelcastInstance")
public HazelcastInstance hazelcastInstance() {
return HazelcastClient.newHazelcastClient();
}
}

View file

@ -0,0 +1,73 @@
package ru.spcex.clearing.securities.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,141 @@
package ru.spcex.clearing.securities.service;
import ru.clearing.classes.statics.data.misc.MoneyMarketSecurity;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityUpdateRequest;
import java.math.BigDecimal;
import java.time.Instant;
class MoneyMarketSecurityFactory {
private Long id = 0L;
private Long securityId = 0L;// (linked to security)
private String description = "tsetse";
private Double lotSize = 1.0;
private Instant startDate = Instant.ofEpochSecond(0);
private Instant endDate = Instant.ofEpochSecond(0);
private BigDecimal nominalValue = BigDecimal.valueOf(1.0);
private Long nominalCurrency = 1L; // (linked to currencyCode)
private String instrumentType = "sdgaga"; // (linked to instrumentType)
private String fullName = "estat";
private Long nominalCurrencyId = 1L;
private String securitySymbol = "sdfafd";
public MoneyMarketSecurityFactory setLotSize(Double lotSize) {
this.lotSize = lotSize;
return this;
}
public MoneyMarketSecurityFactory setNominalCurrencyId(Long nominalCurrencyId) {
this.nominalCurrencyId = nominalCurrencyId;
this.nominalCurrency = nominalCurrencyId;
return this;
}
public MoneyMarketSecurityFactory setId(Long id) {
this.id = id;
return this;
}
public MoneyMarketSecurityFactory setSecurityId(Long securityId) {
this.securityId = securityId;
return this;
}
public MoneyMarketSecurityFactory setDescription(String description) {
this.description = description;
return this;
}
public MoneyMarketSecurityFactory setStartDate(Instant startDate) {
this.startDate = startDate;
return this;
}
public MoneyMarketSecurityFactory setEndDate(Instant endDate) {
this.endDate = endDate;
return this;
}
public MoneyMarketSecurityFactory setNominalValue(BigDecimal nominalValue) {
this.nominalValue = nominalValue;
return this;
}
public MoneyMarketSecurityFactory setNominalCurrency(Long nominalCurrency) {
this.nominalCurrency = nominalCurrency;
this.nominalCurrencyId = nominalCurrency;
return this;
}
public MoneyMarketSecurityFactory setInstrumentType(String instrumentType) {
this.instrumentType = instrumentType;
return this;
}
public MoneyMarketSecurityFactory setFullName(String fullName) {
this.fullName = fullName;
return this;
}
public MoneyMarketSecurityFactory setSecuritySymbol(String securitySymbol) {
this.securitySymbol = securitySymbol;
return this;
}
public MoneyMarketSecurity getMoneyMarketSecurity() {
MoneyMarketSecurity moneyMarketSecurity = new MoneyMarketSecurity();
moneyMarketSecurity.setId(id);
moneyMarketSecurity.setSecurityId(securityId);
moneyMarketSecurity.setDescription(description);
moneyMarketSecurity.setStartDate(startDate.minusSeconds(60 * 60 * 3));
moneyMarketSecurity.setEndDate(endDate.minusSeconds(60 * 60 * 3));
moneyMarketSecurity.setNominalValue(nominalValue);
moneyMarketSecurity.setNominalCurrency(nominalCurrency);
moneyMarketSecurity.setInstrumentType(instrumentType);
moneyMarketSecurity.setFullName(fullName);
moneyMarketSecurity.setSecuritySymbol(securitySymbol);
return moneyMarketSecurity;
}
public MoneyMarketSecurityUpdateRequest getMoneyMarketSecurityUpdateRequest() {
MoneyMarketSecurityUpdateRequest moneyMarketSecurityUpdateRequest
= new MoneyMarketSecurityUpdateRequest();
moneyMarketSecurityUpdateRequest.setId(id);
moneyMarketSecurityUpdateRequest.setEndDate(endDate);
moneyMarketSecurityUpdateRequest.setNominalValue(nominalValue.doubleValue());
moneyMarketSecurityUpdateRequest.setNominalCurrencyId(nominalCurrencyId);
moneyMarketSecurityUpdateRequest.setInstrumentType(instrumentType);
moneyMarketSecurityUpdateRequest.setFullName(fullName);
return moneyMarketSecurityUpdateRequest;
}
public CommonDeleteRequest getCommonDeleteRequest() {
CommonDeleteRequest commonDeleteRequest = new CommonDeleteRequest();
commonDeleteRequest.setId(id);
return commonDeleteRequest;
}
public MoneyMarketSecurityNewRequest getMoneyMarketSecurityNewRequest() {
MoneyMarketSecurityNewRequest keyRequest = new MoneyMarketSecurityNewRequest();
keyRequest.setLotSize(lotSize);
keyRequest.setStartDate(startDate);
keyRequest.setEndDate(endDate);
keyRequest.setNominalValue(nominalValue.doubleValue());
keyRequest.setNominalCurrencyId(nominalCurrencyId);
keyRequest.setInstrumentType(instrumentType);
keyRequest.setFullName(fullName);
keyRequest.setSecuritySymbol(securitySymbol);
return keyRequest;
}
}

View file

@ -0,0 +1,297 @@
package ru.spcex.clearing.securities.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryAddedListener;
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.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.misc.KeyRate;
import ru.clearing.classes.statics.data.misc.MoneyMarketSecurity;
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.securitites.MoneyMarketSecurityNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.securitites.MoneyMarketSecurityUpdateRequest;
import ru.spcex.clearing.securities.config.HazelcastInstanceTestConfiguration;
import ru.spcex.clearing.securities.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.securities.service.cud.MoneyMarketSecurityService;
import ru.spcex.clearing.securities.utils.MatcherFactory;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class,
HazelcastInstanceTestConfiguration.class})
public class MoneyMarketSecurityServiceTest {
static final ObjectMapper objectMapper = new ObjectMapper();
private MockConsumer<String, Object> kafkaMockQueue;
private final int TIMEOUT = 1000;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastService;
@Autowired
@Qualifier("hazelcastInstance")
private HazelcastInstance hz;
boolean isUsed;
private void setIsUsed(boolean isUsed) {
this.isUsed = isUsed;
}
private String jsonBaseRequest(BaseRequest baseRequest) {
String jsonBaseRequest;
try {
jsonBaseRequest = objectMapper.writeValueAsString(baseRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return jsonBaseRequest;
}
void initKafka(String topic, int partition, Long offset) {
TopicPartition tp = new TopicPartition(topic, partition);
kafkaMockQueue.schedulePollTask(() -> {
kafkaMockQueue.rebalance(Collections.singletonList(tp));
});
HashMap<TopicPartition, Long> startOffsets = new HashMap<>();
startOffsets.put(tp, offset);
kafkaMockQueue.updateBeginningOffsets(startOffsets);
}
private void startService() throws InterruptedException {
MoneyMarketSecurityService keyRateService =
new MoneyMarketSecurityService(kafkaMockQueue, hazelcastService);
keyRateService.afterPropertiesSet();
}
@Test
public void testNewMoneyMarketSecurity() throws InterruptedException {
final String TOPIC = Consts.DESTINATION_MONEY_MARKET_SECURITY_NEW;
final String MAP = IMDGDistributedNames.Map_MoneyMarketSecurity;
final int PARTITION = 0;
final Long OFFSET = 0L;
final Long REQUEST_ID = 0L;
final MoneyMarketSecurityFactory moneyMarketSecurityFactory = new MoneyMarketSecurityFactory();
final MoneyMarketSecurity moneyMarketSecurityPrediction = moneyMarketSecurityFactory
.getMoneyMarketSecurity();
final MoneyMarketSecurityNewRequest keyRequest = moneyMarketSecurityFactory
.getMoneyMarketSecurityNewRequest();
BaseRequest baseRequest = new BaseRequest();
baseRequest.setRequestPayload(keyRequest);
baseRequest.setId(REQUEST_ID);
baseRequest.setActionType(ActionType.NEW);
String jsonRequest = jsonBaseRequest(baseRequest);
ConsumerRecord<String, Object> consumerRecord =
new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
initKafka(TOPIC, PARTITION, OFFSET);
kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
isUsed = false;
IMap<Long, MoneyMarketSecurity> iMap = hz.getMap(MAP);
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryAddedListener<Long, MoneyMarketSecurity>) entryEvent -> {
System.out.println("Checking Equality");
MoneyMarketSecurity moneyMarketSecurityResult = entryEvent.getValue();
moneyMarketSecurityPrediction.setId(entryEvent.getKey());
MatcherFactory.Matcher<MoneyMarketSecurity> matcher = MatcherFactory
.usingIgnoringFieldsComparator("id", "securityId", "description");
matcher.assertMatch(moneyMarketSecurityResult, moneyMarketSecurityPrediction);
System.out.println("ok");
setIsUsed(true);
synchronized (waiter) {
waiter.notify();
}
}, true);
startService();
synchronized (waiter) {
waiter.wait(TIMEOUT);
}
Assertions.assertEquals(true, isUsed);
iMap.removeEntryListener(listenerID);
}
@Test
public void testDeleteKeyRate() throws InterruptedException {
final String TOPIC = Consts.DESTINATION_MONEY_MARKET_SECURITY_DELETE;
final String MAP = IMDGDistributedNames.Map_MoneyMarketSecurity;
final int PARTITION = 0;
final Long ID = 1L;
final Long OFFSET = 0L;
final Long REQUEST_ID = 2L;
final MoneyMarketSecurityFactory moneyMarketSecurityFactory =
new MoneyMarketSecurityFactory()
.setId(ID);
final MoneyMarketSecurity initialMoneyMarketSecurity = moneyMarketSecurityFactory
.getMoneyMarketSecurity();
final CommonDeleteRequest keyRequest = moneyMarketSecurityFactory
.getCommonDeleteRequest();
BaseRequest baseRequest = new BaseRequest();
baseRequest.setRequestPayload(keyRequest);
baseRequest.setId(REQUEST_ID);
baseRequest.setActionType(ActionType.DELETE);
String jsonRequest = jsonBaseRequest(baseRequest);
ConsumerRecord<String, Object> consumerRecord =
new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
initKafka(TOPIC, PARTITION, OFFSET);
kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
isUsed = false;
IMap<Long, MoneyMarketSecurity> iMap = hz.getMap(MAP);
iMap.put(ID, initialMoneyMarketSecurity);
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryRemovedListener<Long, KeyRate>) entryEvent -> {
System.out.println("Checking If removed..");
Assertions.assertEquals(ID, entryEvent.getKey());
System.out.println("ok");
setIsUsed(true);
synchronized (waiter) {
waiter.notify();
}
}, false);
startService();
synchronized (waiter) {
waiter.wait(TIMEOUT);
}
Assertions.assertEquals(true, isUsed);
iMap.removeEntryListener(listenerID);
}
@Test
public void testUpdateKeyRate() throws InterruptedException {
final String TOPIC = Consts.DESTINATION_MONEY_MARKET_SECURITY_UPDATE;
final String MAP = IMDGDistributedNames.Map_MoneyMarketSecurity;
final int PARTITION = 0;
final Long ID = 1L;
final Long OFFSET = 0L;
final Long REQUEST_ID = 1L;
final MoneyMarketSecurityFactory moneyMarketSecurityFactory =
new MoneyMarketSecurityFactory()
.setId(ID);
final MoneyMarketSecurity initialMoneyMarketSecurity = moneyMarketSecurityFactory
.getMoneyMarketSecurity();
moneyMarketSecurityFactory
.setFullName("sfgsdfg")
.setInstrumentType("qwerqwe")
.setNominalCurrencyId(2L)
.setNominalValue(BigDecimal.valueOf(2.0))
.setEndDate(Instant.ofEpochSecond(24 * 3600));
final MoneyMarketSecurity moneyMarketSecurityPrediction =
moneyMarketSecurityFactory.getMoneyMarketSecurity();
final MoneyMarketSecurityUpdateRequest keyRequest =
moneyMarketSecurityFactory.getMoneyMarketSecurityUpdateRequest();
BaseRequest baseRequest = new BaseRequest();
baseRequest.setRequestPayload(keyRequest);
baseRequest.setId(REQUEST_ID);
baseRequest.setActionType(ActionType.UPDATE);
String jsonRequest = jsonBaseRequest(baseRequest);
ConsumerRecord<String, Object> consumerRecord =
new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
initKafka(TOPIC, PARTITION, OFFSET);
kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
IMap<Long, MoneyMarketSecurity> iMap = hz.getMap(MAP);
iMap.put(ID, initialMoneyMarketSecurity);
isUsed = false;
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryUpdatedListener<Long, MoneyMarketSecurity>) entryEvent -> {
System.out.println("Checking Equality..");
MoneyMarketSecurity moneyMarketSecurityResult = entryEvent.getValue();
MatcherFactory.Matcher<MoneyMarketSecurity> matcher = MatcherFactory
.usingIgnoringFieldsComparator("id");
matcher.assertMatch(moneyMarketSecurityResult, moneyMarketSecurityPrediction);
System.out.println("Ok");
setIsUsed(true);
synchronized (waiter) {
waiter.notify();
}
}, true);
startService();
synchronized (waiter) {
waiter.wait(TIMEOUT);
}
Assertions.assertEquals(true, isUsed);
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,38 @@
package ru.spcex.clearing.securities.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

@ -32,10 +32,50 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View file

@ -0,0 +1,23 @@
package ru.spcex.clearing.utility.config;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.config.Config;
import com.hazelcast.config.JoinConfig;
import com.hazelcast.config.MulticastConfig;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Random;
@Configuration
public class HazelcastInstanceTestConfiguration {
@Bean(name = "hazelcastInstance")
public HazelcastInstance hazelcastInstance() {
return HazelcastClient.newHazelcastClient();
}
}

View file

@ -0,0 +1,73 @@
package ru.spcex.clearing.utility.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,79 @@
package ru.spcex.clearing.utility.service;
import ru.clearing.classes.statics.data.misc.KeyRate;
import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateUpdateRequest;
import java.time.Instant;
class KeyRateFactory {
Instant startDate = Instant.ofEpochSecond(0);
Instant endDate = Instant.ofEpochSecond(0);
String document = "Test";
double rate = 0.5;
Long id = 0L;
KeyRateFactory setRate(double rate) {
this.rate = rate;
return this;
}
KeyRateFactory setEndDate(Instant endDate) {
this.endDate = endDate;
return this;
}
KeyRateFactory setId(Long id) {
this.id = id;
return this;
}
KeyRateFactory setDocument(String document) {
this.document = document;
return this;
}
KeyRateFactory setStartDate(Instant startDate) {
this.startDate = startDate;
return this;
}
public KeyRate getKeyRate() {
KeyRate keyRatePrediction = new KeyRate();
keyRatePrediction.setId(id);
keyRatePrediction.setDocument(document);
keyRatePrediction.setEndDate(endDate.minusSeconds(60 * 60 * 3));
keyRatePrediction.setStartDate(startDate.minusSeconds(60 * 60 * 3));
keyRatePrediction.setRate(rate);
return keyRatePrediction;
}
public KeyRateUpdateRequest getKeyRateUpdateRequest() {
KeyRateUpdateRequest keyRateUpdateRequest = new KeyRateUpdateRequest();
keyRateUpdateRequest.setId(id);
keyRateUpdateRequest.setKeyRate(rate);
keyRateUpdateRequest.setDocument(document);
keyRateUpdateRequest.setStartDate(startDate);
keyRateUpdateRequest.setEndDate(endDate);
return keyRateUpdateRequest;
}
public CommonDeleteRequest getCommonDeleteRequest() {
CommonDeleteRequest commonDeleteRequest = new CommonDeleteRequest();
commonDeleteRequest.setId(id);
return commonDeleteRequest;
}
public KeyRateNewRequest getKeyRateNewRequest() {
KeyRateNewRequest keyRequest = new KeyRateNewRequest();
keyRequest.setKeyRate(rate);
keyRequest.setDocument(document);
keyRequest.setEndDate(endDate);
keyRequest.setStartDate(startDate);
return keyRequest;
}
}

View file

@ -0,0 +1,285 @@
package ru.spcex.clearing.utility.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.map.listener.EntryAddedListener;
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.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.misc.KeyRate;
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.utilities.KeyRateNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.utilities.KeyRateUpdateRequest;
import ru.spcex.clearing.utility.config.HazelcastInstanceTestConfiguration;
import ru.spcex.clearing.utility.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.utility.utils.MatcherFactory;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
HazelcastServiceTestConfiguration.class,
HazelcastInstanceTestConfiguration.class})
public class KeyRateServiceTest {
static final ObjectMapper objectMapper = new ObjectMapper();
private MockConsumer<String, Object> kafkaMockQueue;
private final int TIMEOUT = 1000;
@Autowired
@Qualifier("hazelcastServiceTest")
private HazelcastService hazelcastService;
@Autowired
@Qualifier("hazelcastInstance")
private HazelcastInstance hz;
boolean isUsed;
private void setIsUsed(boolean isUsed) {
this.isUsed = isUsed;
}
private String jsonBaseRequest(BaseRequest baseRequest) {
String jsonBaseRequest;
try {
jsonBaseRequest = objectMapper.writeValueAsString(baseRequest);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return jsonBaseRequest;
}
void initKafka(String topic, int partition, Long offset) {
TopicPartition tp = new TopicPartition(topic, partition);
kafkaMockQueue.schedulePollTask(() -> {
kafkaMockQueue.rebalance(Collections.singletonList(tp));
});
HashMap<TopicPartition, Long> startOffsets = new HashMap<>();
startOffsets.put(tp, offset);
kafkaMockQueue.updateBeginningOffsets(startOffsets);
}
private void startService() throws InterruptedException {
KeyRateService keyRateService =
new KeyRateService(kafkaMockQueue, hazelcastService);
keyRateService.afterPropertiesSet();
}
@Test
public void testNewKeyRate() throws InterruptedException {
final String TOPIC = Consts.DESTINATION_KEY_RATE_NEW;
final String MAP = IMDGDistributedNames.Map_KeyRate;
final int PARTITION = 0;
final Long OFFSET = 0L;
final Long REQUEST_ID = 0L;
final KeyRateFactory keyRateFactory = new KeyRateFactory();
final KeyRate keyRatePrediction = keyRateFactory.getKeyRate();
final KeyRateNewRequest keyRequest = keyRateFactory.getKeyRateNewRequest();
BaseRequest baseRequest = new BaseRequest();
baseRequest.setRequestPayload(keyRequest);
baseRequest.setId(REQUEST_ID);
baseRequest.setActionType(ActionType.NEW);
String jsonRequest = jsonBaseRequest(baseRequest);
ConsumerRecord<String, Object> consumerRecord =
new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
initKafka(TOPIC, PARTITION, OFFSET);
kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
isUsed = false;
IMap<Long, KeyRate> iMap = hz.getMap(MAP);
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryAddedListener<Long, KeyRate>) entryEvent -> {
System.out.println("Checking Equality");
KeyRate keyRateResult = entryEvent.getValue();
keyRatePrediction.setId(entryEvent.getKey());
MatcherFactory.Matcher<KeyRate> matcher = MatcherFactory
.usingIgnoringFieldsComparator("id");
matcher.assertMatch(keyRateResult, keyRatePrediction);
System.out.println("ok");
setIsUsed(true);
synchronized (waiter) {
waiter.notify();
}
}, true);
startService();
synchronized (waiter) {
waiter.wait(TIMEOUT);
}
Assertions.assertEquals(true, isUsed);
iMap.removeEntryListener(listenerID);
}
@Test
public void testDeleteKeyRate() throws InterruptedException {
final String TOPIC = Consts.DESTINATION_KEY_RATE_DELETE;
final String MAP = IMDGDistributedNames.Map_KeyRate;
final int PARTITION = 0;
final Long ID = 1L;
final Long OFFSET = 0L;
final Long REQUEST_ID = 2L;
final KeyRateFactory keyRateFactory = new KeyRateFactory()
.setId(ID);
final KeyRate initialKeyRate = keyRateFactory.getKeyRate();
final CommonDeleteRequest keyRequest = keyRateFactory.getCommonDeleteRequest();
BaseRequest baseRequest = new BaseRequest();
baseRequest.setRequestPayload(keyRequest);
baseRequest.setId(REQUEST_ID);
baseRequest.setActionType(ActionType.DELETE);
String jsonRequest = jsonBaseRequest(baseRequest);
ConsumerRecord<String, Object> consumerRecord =
new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
initKafka(TOPIC, PARTITION, OFFSET);
kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
isUsed = false;
IMap<Long, KeyRate> iMap = hz.getMap(MAP);
iMap.put(ID, initialKeyRate);
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryRemovedListener<Long, KeyRate>) entryEvent -> {
System.out.println("Checking If removed..");
Assertions.assertEquals(ID, entryEvent.getKey());
System.out.println("ok");
setIsUsed(true);
synchronized (waiter) {
waiter.notify();
}
}, false);
startService();
synchronized (waiter) {
waiter.wait(TIMEOUT);
}
Assertions.assertEquals(true, isUsed);
iMap.removeEntryListener(listenerID);
}
@Test
public void testUpdateKeyRate() throws InterruptedException {
final String TOPIC = Consts.DESTINATION_KEY_RATE_UPDATE;
final String MAP = IMDGDistributedNames.Map_KeyRate;
final int PARTITION = 0;
final Long ID = 1L;
final Long OFFSET = 0L;
final Long REQUEST_ID = 1L;
final KeyRateFactory keyRateFactory = new KeyRateFactory()
.setId(ID);
final KeyRate initialKeyRate = keyRateFactory.getKeyRate();
keyRateFactory
.setRate(5)
.setEndDate(Instant.ofEpochSecond(24 * 3600))
.setStartDate(Instant.ofEpochSecond(24 * 3600))
.setDocument("Update");
final KeyRate keyRatePrediction = keyRateFactory.getKeyRate();
final KeyRateUpdateRequest keyRequest = keyRateFactory.getKeyRateUpdateRequest();
BaseRequest baseRequest = new BaseRequest();
baseRequest.setRequestPayload(keyRequest);
baseRequest.setId(REQUEST_ID);
baseRequest.setActionType(ActionType.UPDATE);
String jsonRequest = jsonBaseRequest(baseRequest);
ConsumerRecord<String, Object> consumerRecord =
new ConsumerRecord<>(TOPIC, PARTITION, 0, "key", jsonRequest);
kafkaMockQueue = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
initKafka(TOPIC, PARTITION, OFFSET);
kafkaMockQueue.schedulePollTask(() -> kafkaMockQueue.addRecord(consumerRecord));
IMap<Long, KeyRate> iMap = hz.getMap(MAP);
iMap.put(ID, initialKeyRate);
isUsed = false;
Object waiter = new Object();
String listenerID = iMap.addEntryListener((EntryUpdatedListener<Long, KeyRate>) entryEvent -> {
System.out.println("Checking Equality..");
KeyRate keyRateResult = entryEvent.getValue();
MatcherFactory.Matcher<KeyRate> matcher = MatcherFactory
.usingIgnoringFieldsComparator("id");
matcher.assertMatch(keyRateResult, keyRatePrediction);
System.out.println("Ok");
setIsUsed(true);
synchronized (waiter) {
waiter.notify();
}
}, true);
startService();
synchronized (waiter) {
waiter.wait(TIMEOUT);
}
Assertions.assertEquals(true, isUsed);
iMap.removeEntryListener(listenerID);
}
}

View file

@ -0,0 +1,37 @@
package ru.spcex.clearing.utility.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

@ -22,7 +22,7 @@ public class KeyRateNewRequest {
@JsonProperty
public String document;
public Double getKeyRate() {
public double getKeyRate() {
return keyRate;
}