diff --git a/clearing-parent/control-service/pom.xml b/clearing-parent/control-service/pom.xml
index 56887fec3..7f82a12c8 100644
--- a/clearing-parent/control-service/pom.xml
+++ b/clearing-parent/control-service/pom.xml
@@ -18,6 +18,7 @@
5.5.2
7.0.1
+ 1.20.2
@@ -83,6 +84,18 @@
test-clearing
test
+
+ org.testcontainers
+ testcontainers
+ ${testcontainers.version}
+ test
+
+
+ org.testcontainers
+ postgresql
+ ${testcontainers.version}
+ test
+
diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java
index 152373461..3386e8034 100644
--- a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java
+++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/model/ResultContainer.java
@@ -58,6 +58,9 @@ public class ResultContainer {
this.quantityDifference = quantityDifference;
}
+ public ResultContainer() {
+ }
+
public Long getSessionId() {
return sessionId;
}
diff --git a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java
index 783a4a908..94d08a768 100644
--- a/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java
+++ b/clearing-parent/control-service/src/main/java/ru/spcex/clearing/control/service/ControlService.java
@@ -4,6 +4,7 @@ import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
+import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
@@ -33,7 +34,7 @@ public class ControlService {
resultDirectory = Path.of(settings.getResultDirectory());
}
- public void generalControl(SessionType sessionType) {
+ public File generalControl(SessionType sessionType) {
log.info("Starting general control with session type {}", sessionType);
ResultContainer resultContainer = switch (sessionType) {
@@ -48,34 +49,41 @@ public class ControlService {
if (resultContainer.getQuantityDifference() != 0) {
resultContainer.setSessionType(sessionType);
- writeToCsvFile(resultContainer);
+ return writeToCsvFile(resultContainer);
}
+
+ return null;
}
- public void internalControl(Long sessionId) {
+ public File internalControl(Long sessionId) {
log.info("Starting internal control with session id {}", sessionId);
ResultContainer resultContainer = controlRepository.getInternalCountDiff(sessionId);
if (resultContainer.getQuantityDifference() != 0) {
resultContainer.setSessionId(sessionId);
- writeToCsvFile(resultContainer);
+ return writeToCsvFile(resultContainer);
}
+
+ return null;
}
- public void internalControlFinl(Long sessionId) {
+ public File internalControlFinl(Long sessionId) {
log.info("Starting internal control FINL with session id {}", sessionId);
ResultContainer resultContainer = controlRepository.getFinlInternalCountDiff(sessionId);
if (resultContainer.getQuantityDifference() != 0) {
resultContainer.setSessionId(sessionId);
- writeToCsvFile(resultContainer);
+ return writeToCsvFile(resultContainer);
}
+
+ return null;
}
- private void writeToCsvFile(ResultContainer resultContainer) {
- try (Writer writer = new FileWriter(resultDirectory.resolve("result-" + Instant.now().getEpochSecond() + ".csv").toFile())) {
+ private File writeToCsvFile(ResultContainer resultContainer) {
+ File resultFile = resultDirectory.resolve("result-" + Instant.now().toEpochMilli() + ".csv").toFile();
+ try (Writer writer = new FileWriter(resultFile)) {
CustomMappingStrategy mappingStrategy = new CustomMappingStrategy<>();
mappingStrategy.setType(ResultContainer.class);
@@ -86,5 +94,6 @@ public class ControlService {
} catch (CsvRequiredFieldEmptyException | CsvDataTypeMismatchException | IOException e) {
log.error(e.getMessage(), e);
}
+ return resultFile;
}
}
diff --git a/clearing-parent/control-service/src/test/java/ru/spcex/clearing/control/config/TestDataSourceConfiguration.java b/clearing-parent/control-service/src/test/java/ru/spcex/clearing/control/config/TestDataSourceConfiguration.java
new file mode 100644
index 000000000..cb8929fd7
--- /dev/null
+++ b/clearing-parent/control-service/src/test/java/ru/spcex/clearing/control/config/TestDataSourceConfiguration.java
@@ -0,0 +1,52 @@
+package ru.spcex.clearing.control.config;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import java.beans.PropertyVetoException;
+import javax.sql.DataSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.testcontainers.containers.PostgreSQLContainer;
+import ru.spcex.clearing.control.config.settings.ControlServiceSettings;
+
+@Configuration
+public class TestDataSourceConfiguration {
+ private final ControlServiceSettings settings;
+
+ public TestDataSourceConfiguration(ControlServiceSettings settings) {
+ this.settings = settings;
+ }
+
+ @Bean
+ public DataSource getDataSource() {
+ PostgreSQLContainer> postgres = new PostgreSQLContainer<>(PostgreSQLContainer.IMAGE);
+ postgres.start();
+
+ ComboPooledDataSource cpds = new ComboPooledDataSource();
+ try {
+ cpds.setDriverClass(postgres.getDriverClassName());
+ cpds.setJdbcUrl(postgres.getJdbcUrl());
+ cpds.setUser(postgres.getUsername());
+ cpds.setPassword(postgres.getPassword());
+
+ cpds.setMaxPoolSize(100);
+ cpds.setMinPoolSize(50);
+ cpds.setAcquireIncrement(5);
+ } catch (PropertyVetoException e) {
+ throw new RuntimeException(e);
+ }
+
+ return cpds;
+ }
+
+ @Bean
+ public JdbcTemplate getJdbcTemplate() {
+ return new JdbcTemplate(getDataSource());
+ }
+
+ @Bean
+ public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
+ return new NamedParameterJdbcTemplate(getDataSource());
+ }
+}
diff --git a/clearing-parent/control-service/src/test/java/ru/spcex/clearing/control/service/ControlServiceTest.java b/clearing-parent/control-service/src/test/java/ru/spcex/clearing/control/service/ControlServiceTest.java
new file mode 100644
index 000000000..ee5370176
--- /dev/null
+++ b/clearing-parent/control-service/src/test/java/ru/spcex/clearing/control/service/ControlServiceTest.java
@@ -0,0 +1,171 @@
+package ru.spcex.clearing.control.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.opencsv.CSVReader;
+import com.opencsv.exceptions.CsvException;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.jdbc.core.JdbcTemplate;
+import ru.spcex.clearing.control.config.TestDataSourceConfiguration;
+import ru.spcex.clearing.control.config.settings.ControlServiceSettings;
+import ru.spcex.clearing.control.mapper.ResultContainerMapper;
+import ru.spcex.clearing.control.model.ResultContainer;
+import ru.spcex.clearing.control.repository.ControlRepository;
+import ru.spcex.platform.enumeration.SessionType;
+
+@SpringBootTest(classes = {
+ TestDataSourceConfiguration.class,
+ ControlService.class,
+ ControlRepository.class,
+ ResultContainerMapper.class,
+ ControlServiceSettings.class
+}, properties = {
+ "control-service.result-directory=src/test/resources"
+})
+@EnableConfigurationProperties
+class ControlServiceTest {
+ @Autowired
+ private ControlService controlService;
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @BeforeEach
+ void setUp() {
+ jdbcTemplate.execute("DROP TABLE IF EXISTS s_trades");
+ jdbcTemplate.execute("DROP TABLE IF EXISTS execution_deposit");
+ jdbcTemplate.execute("DROP TABLE IF EXISTS execution_fond");
+ jdbcTemplate.execute("DROP TABLE IF EXISTS execution_currency");
+ jdbcTemplate.execute("DROP TABLE IF EXISTS payment_instruction");
+ jdbcTemplate.execute("DROP TABLE IF EXISTS s_df03");
+
+ jdbcTemplate.execute("create table s_trades(id bigint not null primary key, created_at timestamp, updated_at timestamp, trade_num bigint, operation varchar(40), class_code varchar(255), trade_date date, sec_code varchar(255), accruedint numeric(72, 18), accruedint2 numeric(72, 18), lower_discount numeric(72, 18), order_num bigint, price numeric(72, 18), price2 numeric(72, 18), repo_rate numeric(72, 18), repo_value numeric(72, 18), repo2_value numeric(72, 18), start_discount numeric(72, 18), ts_commission numeric(72, 18), upper_discount numeric(72, 18), value numeric(72, 18), yield numeric(72, 18), qty numeric(72, 18), qty_pcs numeric(72, 18), trade_date_time timestamp, repo_term bigint, clearing_commission numeric(72, 18), exchange_commission numeric(72, 18), tech_center_commission numeric(72, 18), account varchar(50), broker_ref varchar(34), client_code varchar(255), settle_code varchar(50), user_id varchar(32), exchange_code varchar(64), firm_id varchar(255), firm_name varchar(255), cp_firm_id varchar(255), cp_firm_name varchar(255), class_name varchar(255), sec_name varchar(255), settle_date date, settle_currency varchar(4), trade_currency varchar(4), trade_time_ms bigint, bank_acc_id varchar(12), section varchar(4));");
+ jdbcTemplate.execute("create table execution_deposit(exchange_execution_id bigint,exchange_execution_time timestamp,trading_date date,trading_clearing_registry_id bigint,party_trading_clearing_registry varchar(20),market varchar(8),price numeric(72, 18),lots numeric(72, 2),quantity numeric(72, 2),first_leg_amount numeric(72, 2),second_leg_amount numeric(72, 2),interest_amount numeric(72, 2),side varchar(4),settlement_currency varchar(4),company_id bigint,duration bigint,first_leg_settlement_date date,second_leg_settlement_date date,first_leg_settlement_code varchar(12),second_leg_settlement_code varchar(12),security_full_name varchar(255),security_symbol varchar(255),security_code varchar(255),security_id bigint,contract varchar(255),counter_party_id bigint,counter_party_trading_clearing_registry_id bigint,counter_party_trading_clearing_registry varchar(20),coverage_status varchar(4),session_id bigint,id bigint not null primary key, created_at timestamp, updated_at timestamp, clearing_date date);");
+ jdbcTemplate.execute("create table execution_fond(id bigint not null primary key, created_at timestamp, updated_at timestamp, clearing_date date, exchange_execution_id bigint, side varchar(4), market varchar(4), trading_date date, security_symbol varchar(255), security_id bigint, interest_amount numeric(72, 2), exchange_order_id bigint, price numeric(72, 18), settlement_amount numeric(72, 2), lots numeric(72, 2), quantity numeric(72, 2), exchange_execution_time timestamp, duration bigint, trading_clearing_registry_id bigint, party_trading_clearing_registry varchar(20), comment varchar(255), client_code_id bigint, settlement_code varchar(12), company_id bigint, counter_party_id bigint, counter_party_trading_clearing_registry_id bigint, counter_party_trading_clearing_registry varchar(20), security_full_name varchar(255), settlement_date date, settlement_currency varchar(4), exchange_execution_microseconds timestamp, coverage_status varchar(4), session_id bigint);");
+ jdbcTemplate.execute("create table execution_currency( exchange_execution_id bigint, exchange_execution_time timestamp, exchange_execution_microseconds timestamp, trading_date date, settlement_date date, settlement_code varchar(12), security_id bigint, security_symbol varchar(255), security_name varchar(255), company_id bigint, party_trading_clearing_registry_id bigint, party_trading_clearing_registry varchar(20), counter_party_id bigint, counter_party_trading_clearing_registry_id bigint, counter_party_trading_clearing_registry varchar(20), market varchar(4), price numeric(72, 18), lots numeric(72, 2), settlement_amount numeric(72, 2), quantity numeric(72, 2), side varchar(4), currency_code varchar(4), settlement_organization varchar(255), coverage_status varchar(4), session_id bigint, clearing_date date, id bigint not null primary key, created_at timestamp, updated_at timestamp);");
+ jdbcTemplate.execute("create table payment_instruction( sender_id bigint, addressee_id bigint, payee_bic varchar(255), adressee_bic varchar(255), payee_bank_name varchar(255), addressee_bank_name varchar(255), payment_date timestamp, payment_purpose varchar(255), settlement_date date, credit_leg_amount numeric(72, 18), debit_leg_amount numeric(72, 18), credit_leg_account_id bigint, credit_cs_account varchar(255), credit_leg_account varchar(50), debit_leg_account_id bigint, debit_cs_account varchar(255), debit_leg_account varchar(50), credit_leg_direction varchar(4), debit_leg_direction varchar(4), credit_leg_currency_code varchar(4), debit_leg_currency_code varchar(4), credit_leg_security_id bigint, debit_leg_security_id bigint, transaction_status varchar(4), document_number varchar(255), id bigint not null primary key, created_at timestamp, updated_at timestamp, clearing_date date, session_id bigint);");
+ jdbcTemplate.execute("create table s_df03( id bigint not null primary key, seg_type varchar(1), doc_type varchar(4), docnm_ref varchar(16), docnmprev varchar(16), c_acc_deb varchar(35), sbanknam1 varchar(35), sbanknam2 varchar(35), sbanknam3 varchar(35), sbanknam4 varchar(35), sbanknam5 varchar(35), c_acc_cred varchar(35), rbanknam1 varchar(35), rbanknam2 varchar(35), rbanknam3 varchar(35), rbanknam4 varchar(35), rbanknam5 varchar(35), pay_date varchar(8), pay_val varchar(12), sum_deb varchar(22), specif_1 varchar(255), imp_result varchar(3), file_name varchar(255), generation_time timestamp, generation_id bigint, payment_instruction_id bigint);");
+
+ jdbcTemplate.execute("insert into s_trades (id, created_at, section) values (1, NOW(), 'FINL'), (2, NOW(), 'FOND'), (3, NOW(), 'CURR');");
+ jdbcTemplate.execute("insert into execution_deposit (id, created_at) values (1, NOW()), (2, NOW());");
+ jdbcTemplate.execute("insert into execution_fond (id, created_at) values (1, NOW()), (2, NOW());");
+ jdbcTemplate.execute("insert into execution_currency (id, created_at) values (1, NOW()), (2, NOW());");
+ jdbcTemplate.execute("insert into payment_instruction (id, created_at, session_id) values (1, NOW(), 1), (2, NOW(), 1);");
+ jdbcTemplate.execute("insert into s_df03 (id, generation_time, payment_instruction_id) values (1, NOW(), 1), (2, NOW(), 1);");
+ }
+
+ @Test
+ void generalControl_shouldReturnFINLCSVFile() {
+ ResultContainer resultContainer = new ResultContainer(null, SessionType.FINL, "s_trades", 3L, "execution_deposit", 2L, 1L);
+
+ File resultFile = controlService.generalControl(SessionType.FINL);
+ assertThat(resultFile).isNotNull();
+
+ ResultContainer actual;
+ try (Reader reader = new FileReader(resultFile);
+ CSVReader csvReader = new CSVReader(reader)) {
+ actual = parseResultContainer(csvReader.readAll());
+ } catch (IOException | CsvException e) {
+ throw new RuntimeException(e);
+ }
+ resultFile.delete();
+
+ assertThat(actual).isEqualTo(resultContainer);
+ }
+
+ @Test
+ void generalControl_shouldReturnIPOBCSVFile() {
+ ResultContainer resultContainer = new ResultContainer(null, SessionType.IPOB, "s_trades", 1L, "execution_fond", 2L, -1L);
+
+ File resultFile = controlService.generalControl(SessionType.IPOB);
+ assertThat(resultFile).isNotNull();
+
+ ResultContainer actual;
+ try (Reader reader = new FileReader(resultFile);
+ CSVReader csvReader = new CSVReader(reader)) {
+ actual = parseResultContainer(csvReader.readAll());
+ } catch (IOException | CsvException e) {
+ throw new RuntimeException(e);
+ }
+ resultFile.delete();
+
+ assertThat(actual).isEqualTo(resultContainer);
+ }
+
+ @Test
+ void generalControl_shouldReturnCURRCSVFile() {
+ ResultContainer resultContainer = new ResultContainer(null, SessionType.CURR, "s_trades", 1L, "execution_currency", 2L, -1L);
+
+ File resultFile = controlService.generalControl(SessionType.CURR);
+ assertThat(resultFile).isNotNull();
+
+ ResultContainer actual;
+ try (Reader reader = new FileReader(resultFile);
+ CSVReader csvReader = new CSVReader(reader)) {
+ actual = parseResultContainer(csvReader.readAll());
+ } catch (IOException | CsvException e) {
+ throw new RuntimeException(e);
+ }
+ resultFile.delete();
+
+ assertThat(actual).isEqualTo(resultContainer);
+ }
+
+ @Test
+ void internalControl_shouldReturnInternalControlCSVFile() {
+ ResultContainer resultContainer = new ResultContainer(1L, null, null, 1L, null, 2L, 3L);
+
+ File resultFile = controlService.internalControl(1L);
+ assertThat(resultFile).isNotNull();
+
+ ResultContainer actual;
+ try (Reader reader = new FileReader(resultFile);
+ CSVReader csvReader = new CSVReader(reader)) {
+ actual = parseResultContainer(csvReader.readAll());
+ } catch (IOException | CsvException e) {
+ throw new RuntimeException(e);
+ }
+ resultFile.delete();
+
+ assertThat(actual).isEqualTo(resultContainer);
+ }
+
+ @Test
+ void internalControlFinl_shouldReturnInternalControlCSVFile() {
+ ResultContainer resultContainer = new ResultContainer(1L, null, "payment_instruction", 2L, "s_df03", 3L, -1L);
+
+ File resultFile = controlService.internalControlFinl(1L);
+ assertThat(resultFile).isNotNull();
+
+ ResultContainer actual;
+ try (Reader reader = new FileReader(resultFile);
+ CSVReader csvReader = new CSVReader(reader)) {
+ actual = parseResultContainer(csvReader.readAll());
+ } catch (IOException | CsvException e) {
+ throw new RuntimeException(e);
+ }
+ resultFile.delete();
+
+ assertThat(actual).isEqualTo(resultContainer);
+ }
+
+ private ResultContainer parseResultContainer(List rows) {
+ ResultContainer actual = new ResultContainer();
+ actual.setSessionId(rows.get(1)[0].isBlank() ? null : Long.valueOf(rows.get(1)[0]));
+ actual.setSessionType(rows.get(1)[1].isBlank() ? null : SessionType.valueOf(rows.get(1)[1]));
+ actual.setFirstTableTitle(rows.get(1)[2].isBlank() ? null : rows.get(1)[2]);
+ actual.setFirstTableRecordQuantity(rows.get(1)[3].isBlank() ? null : Long.valueOf(rows.get(1)[3]));
+ actual.setSecondTableRecordTitle(rows.get(1)[4].isBlank() ? null : rows.get(1)[4]);
+ actual.setSecondTableRecordQuantity(rows.get(1)[5].isBlank() ? null : Long.valueOf(rows.get(1)[5]));
+ actual.setQuantityDifference(rows.get(1)[6].isBlank() ? null : Long.valueOf(rows.get(1)[6]));
+ return actual;
+ }
+}
\ No newline at end of file
diff --git a/clearing-parent/control-service/src/test/resources/.gitkeep b/clearing-parent/control-service/src/test/resources/.gitkeep
new file mode 100644
index 000000000..e69de29bb