diff --git a/.editorconfig b/.editorconfig
index ad78e9e..0b4240b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,2 +1,4 @@
[*.{kt,kts}]
-ktlint_disabled_rules=no-wildcard-imports
+ktlint_standard_no-wildcard-imports = disabled
+ktlint_standard_trailing-comma-on-declaration-site = disabled
+ktlint_standard_trailing-comma-on-call-site = disabled
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cfbd1fe..6ebd1d8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,4 +7,4 @@ on:
jobs:
build:
- uses: valitydev/java-workflow/.github/workflows/maven-service-build.yml@v2
\ No newline at end of file
+ uses: valitydev/java-workflow/.github/workflows/maven-service-build.yml@v3
\ No newline at end of file
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 1166548..85af119 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -7,7 +7,9 @@ on:
jobs:
build-and-deploy:
- uses: valitydev/java-workflow/.github/workflows/maven-service-deploy.yml@v2
+ uses: valitydev/java-workflow/.github/workflows/maven-service-deploy.yml@v3
+ with:
+ ignore-coverage: true
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
mm-webhook-url: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index cbcf2bf..aa36045 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
dev.vality
service-parent-pom
- 2.0.3
+ 3.1.0
rate-boss
0.0.1-SNAPSHOT
@@ -14,8 +14,8 @@
8022
8023
- 17
- 1.7.10
+ 21
+ 2.1.21
1.17.3
${server.port} ${management.port}
5432
@@ -94,7 +94,7 @@
dev.vality.geck
common
- 0.0.1
+ 1.0.2
@@ -102,6 +102,10 @@
org.flywaydb
flyway-core
+
+ org.flywaydb
+ flyway-database-postgresql
+
org.postgresql
postgresql
@@ -150,6 +154,10 @@
1.4
pom
+
+ jakarta.servlet
+ jakarta.servlet-api
+
@@ -238,7 +246,7 @@
3.7.1
- dev.vality.maven.plugins
+ dev.crashteam.maven.plugins
pg-embedded-plugin
1.0.1
@@ -258,12 +266,19 @@
PG_server_stop
- compile
+ generate-resources
stop
+
+
+ commons-io
+ commons-io
+ 2.18.0
+
+
org.flywaydb
@@ -332,7 +347,6 @@
org.jetbrains.kotlin
kotlin-maven-plugin
- ${kotlin.version}
-Xjsr305=strict
@@ -341,7 +355,6 @@
spring
jpa
- 1.8
@@ -386,7 +399,7 @@
com.github.gantsign.maven
ktlint-maven-plugin
- 1.15.1
+ 3.5.0
validate
diff --git a/src/main/kotlin/dev/vality/rateboss/client/cbr/CbrApiClient.kt b/src/main/kotlin/dev/vality/rateboss/client/cbr/CbrApiClient.kt
index bea67ec..05e3235 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/cbr/CbrApiClient.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/cbr/CbrApiClient.kt
@@ -15,9 +15,8 @@ import java.time.format.DateTimeFormatter
@Component
class CbrApiClient(
private val restTemplate: RestTemplate,
- private val ratesProperties: RatesProperties
+ private val ratesProperties: RatesProperties,
) {
-
fun getExchangeRates(time: Instant): CbrExchangeRateData {
val baseUrl = ratesProperties.source.cbr.rootUrl
val timezone = ratesProperties.source.cbr.timeZone
@@ -26,13 +25,15 @@ class CbrApiClient(
return restTemplate.exchange(url, HttpMethod.GET, HttpEntity(null, null)).body!!
}
- private fun buildUrl(endpoint: String, date: LocalDate): String {
- return UriComponentsBuilder
+ private fun buildUrl(
+ endpoint: String,
+ date: LocalDate,
+ ): String =
+ UriComponentsBuilder
.fromUriString(endpoint)
.queryParam("date_req", date.format(DATE_TIME_FORMATTER))
.build()
.toUriString()
- }
companion object {
val DATE_TIME_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
diff --git a/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrBigDecimalXmlAdapter.kt b/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrBigDecimalXmlAdapter.kt
index 11437e8..fbb8e79 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrBigDecimalXmlAdapter.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrBigDecimalXmlAdapter.kt
@@ -4,14 +4,10 @@ import java.math.BigDecimal
import javax.xml.bind.annotation.adapters.XmlAdapter
class CbrBigDecimalXmlAdapter : XmlAdapter() {
-
- override fun unmarshal(stringValue: String?): BigDecimal? {
- return stringValue?.let {
+ override fun unmarshal(stringValue: String?): BigDecimal? =
+ stringValue?.let {
BigDecimal(it.replace(',', '.'))
}
- }
- override fun marshal(bigDecimalValue: BigDecimal?): String? {
- return bigDecimalValue?.toString()?.replace('.', ',')
- }
+ override fun marshal(bigDecimalValue: BigDecimal?): String? = bigDecimalValue?.toString()?.replace('.', ',')
}
diff --git a/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrLocalDateXmlAdapter.kt b/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrLocalDateXmlAdapter.kt
index d13a71a..a270f9a 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrLocalDateXmlAdapter.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/cbr/adapter/CbrLocalDateXmlAdapter.kt
@@ -5,18 +5,15 @@ import java.time.format.DateTimeFormatter
import javax.xml.bind.annotation.adapters.XmlAdapter
class CbrLocalDateXmlAdapter : XmlAdapter() {
-
- override fun unmarshal(stringValue: String?): LocalDate? {
- return stringValue?.let {
+ override fun unmarshal(stringValue: String?): LocalDate? =
+ stringValue?.let {
LocalDate.from(DATE_FORMATTER.parse(it))
}
- }
- override fun marshal(dateValue: LocalDate?): String? {
- return dateValue?.let {
+ override fun marshal(dateValue: LocalDate?): String? =
+ dateValue?.let {
DATE_FORMATTER.format(it)
}
- }
companion object {
val DATE_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
diff --git a/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrCurrencyData.kt b/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrCurrencyData.kt
index 4b2e725..bd9c8a0 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrCurrencyData.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrCurrencyData.kt
@@ -8,7 +8,6 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
@XmlRootElement(name = "Valute")
@XmlAccessorType(XmlAccessType.FIELD)
class CbrCurrencyData {
-
@XmlAttribute(name = "ID")
var id: String? = null
diff --git a/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrExchangeRateData.kt b/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrExchangeRateData.kt
index 863cb80..d6fb8bf 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrExchangeRateData.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/cbr/model/CbrExchangeRateData.kt
@@ -8,7 +8,6 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
@XmlRootElement(name = "ValCurs")
@XmlAccessorType(XmlAccessType.FIELD)
class CbrExchangeRateData {
-
@XmlAttribute
var name: String? = null
diff --git a/src/main/kotlin/dev/vality/rateboss/client/fixer/FixerApiClient.kt b/src/main/kotlin/dev/vality/rateboss/client/fixer/FixerApiClient.kt
index c6c56e6..64bfa02 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/fixer/FixerApiClient.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/fixer/FixerApiClient.kt
@@ -13,26 +13,31 @@ import org.springframework.web.util.UriComponentsBuilder
@Component
class FixerApiClient(
private val ratesProperties: RatesProperties,
- private val restTemplate: RestTemplate
+ private val restTemplate: RestTemplate,
) {
-
- fun getLatest(base: String, symbols: String? = null): FixerLatestResponse {
- val urlTemplate = UriComponentsBuilder.fromHttpUrl(ratesProperties.source.fixer.rootUrl).apply {
- path("/latest")
- queryParam("base", base)
- if (symbols != null) {
- queryParam("symbols", symbols)
+ fun getLatest(
+ base: String,
+ symbols: String? = null,
+ ): FixerLatestResponse {
+ val urlTemplate =
+ UriComponentsBuilder.fromHttpUrl(ratesProperties.source.fixer.rootUrl).apply {
+ path("/latest")
+ queryParam("base", base)
+ if (symbols != null) {
+ queryParam("symbols", symbols)
+ }
+ encode()
+ toUriString()
+ }
+ val httpHeaders =
+ HttpHeaders().apply {
+ set("apiKey", ratesProperties.source.fixer.apiKey)
}
- encode()
- toUriString()
- }
- val httpHeaders = HttpHeaders().apply {
- set("apiKey", ratesProperties.source.fixer.apiKey)
- }
- return restTemplate.exchange(
- urlTemplate.toUriString(),
- HttpMethod.GET,
- HttpEntity(null, httpHeaders)
- ).body!!
+ return restTemplate
+ .exchange(
+ urlTemplate.toUriString(),
+ HttpMethod.GET,
+ HttpEntity(null, httpHeaders),
+ ).body!!
}
}
diff --git a/src/main/kotlin/dev/vality/rateboss/client/fixer/model/FixerLatestResponse.kt b/src/main/kotlin/dev/vality/rateboss/client/fixer/model/FixerLatestResponse.kt
index 7b43dfe..5fd3dd6 100644
--- a/src/main/kotlin/dev/vality/rateboss/client/fixer/model/FixerLatestResponse.kt
+++ b/src/main/kotlin/dev/vality/rateboss/client/fixer/model/FixerLatestResponse.kt
@@ -8,5 +8,5 @@ data class FixerLatestResponse(
val date: LocalDate?,
val rates: Map?,
val success: Boolean,
- val timestamp: Long?
+ val timestamp: Long?,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/config/AppConfig.kt b/src/main/kotlin/dev/vality/rateboss/config/AppConfig.kt
index 01d559a..bed1d29 100644
--- a/src/main/kotlin/dev/vality/rateboss/config/AppConfig.kt
+++ b/src/main/kotlin/dev/vality/rateboss/config/AppConfig.kt
@@ -10,14 +10,13 @@ import org.springframework.web.client.RestTemplate
@Configuration
class AppConfig {
-
@Bean
fun restTemplate() = RestTemplate()
@Bean
fun retryTemplate(
@Value("\${retryTemplate.backOffPeriod}") backOffPeriod: Long,
- @Value("\${retryTemplate.maxAttempts}") maxAttempts: Int
+ @Value("\${retryTemplate.maxAttempts}") maxAttempts: Int,
): RetryTemplate {
val retryTemplate = RetryTemplate()
val fixedBackOffPolicy = FixedBackOffPolicy()
diff --git a/src/main/kotlin/dev/vality/rateboss/config/JobConfig.kt b/src/main/kotlin/dev/vality/rateboss/config/JobConfig.kt
index 79b1846..2924c67 100644
--- a/src/main/kotlin/dev/vality/rateboss/config/JobConfig.kt
+++ b/src/main/kotlin/dev/vality/rateboss/config/JobConfig.kt
@@ -11,7 +11,6 @@ import javax.annotation.PostConstruct
@Configuration
class JobConfig {
-
@Autowired
private lateinit var schedulerFactoryBean: Scheduler
@@ -43,13 +42,13 @@ class JobConfig {
return jobDetail
}
- fun fixerExchangeRateGrabberMasterTrigger(): CronTrigger {
- return TriggerBuilder.newTrigger()
+ fun fixerExchangeRateGrabberMasterTrigger(): CronTrigger =
+ TriggerBuilder
+ .newTrigger()
.forJob(fixerExchangeRateGrabberMasterJob())
.withIdentity(ratesProperties.fixerJob.jobTriggerName)
.withSchedule(CronScheduleBuilder.cronSchedule(ratesProperties.fixerJob.jobCron))
.build()
- }
fun cbrExchangeRateGrabberMasterJob(): JobDetailImpl {
val jobDetail = JobDetailImpl()
@@ -58,11 +57,11 @@ class JobConfig {
return jobDetail
}
- fun cbrExchangeRateGrabberMasterTrigger(): CronTrigger {
- return TriggerBuilder.newTrigger()
+ fun cbrExchangeRateGrabberMasterTrigger(): CronTrigger =
+ TriggerBuilder
+ .newTrigger()
.forJob(cbrExchangeRateGrabberMasterJob())
.withIdentity(ratesProperties.cbrJob.jobTriggerName)
.withSchedule(CronScheduleBuilder.cronSchedule(ratesProperties.cbrJob.jobCron))
.build()
- }
}
diff --git a/src/main/kotlin/dev/vality/rateboss/config/KafkaConfig.kt b/src/main/kotlin/dev/vality/rateboss/config/KafkaConfig.kt
index d431093..5c6d5fa 100644
--- a/src/main/kotlin/dev/vality/rateboss/config/KafkaConfig.kt
+++ b/src/main/kotlin/dev/vality/rateboss/config/KafkaConfig.kt
@@ -15,7 +15,6 @@ import org.springframework.kafka.core.ProducerFactory
@Configuration
class KafkaConfig {
-
@Autowired
lateinit var kafkaProperties: KafkaProperties
@@ -27,7 +26,7 @@ class KafkaConfig {
retryBackoffMs: Long,
batchSize: Int,
acks: String,
- deliveryTimeout: Int
+ deliveryTimeout: Int,
): Map {
val props: MutableMap = HashMap(kafkaProperties.buildProducerProperties())
props[ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java
@@ -41,22 +40,20 @@ class KafkaConfig {
}
@Bean
- fun producerFactory(): ProducerFactory {
- return DefaultKafkaProducerFactory(
+ fun producerFactory(): ProducerFactory =
+ DefaultKafkaProducerFactory(
producerConfigs(
kafkaCustomProperties.producer.maxRetries,
kafkaCustomProperties.producer.retryBackoffMs,
kafkaCustomProperties.producer.batchSize,
ACKS_CONFIG,
- kafkaCustomProperties.producer.deliveryTimeoutMs
- )
+ kafkaCustomProperties.producer.deliveryTimeoutMs,
+ ),
)
- }
@Bean
- fun kafkaTemplate(producerFactory: ProducerFactory): KafkaTemplate {
- return KafkaTemplate(producerFactory)
- }
+ fun kafkaTemplate(producerFactory: ProducerFactory): KafkaTemplate =
+ KafkaTemplate(producerFactory)
private companion object {
const val ACKS_CONFIG = "1"
diff --git a/src/main/kotlin/dev/vality/rateboss/config/QuartzConfig.kt b/src/main/kotlin/dev/vality/rateboss/config/QuartzConfig.kt
index 59313c6..19596c5 100644
--- a/src/main/kotlin/dev/vality/rateboss/config/QuartzConfig.kt
+++ b/src/main/kotlin/dev/vality/rateboss/config/QuartzConfig.kt
@@ -10,7 +10,6 @@ import javax.sql.DataSource
@Configuration
class QuartzConfig {
-
@Autowired
private lateinit var quartzProperties: QuartzProperties
diff --git a/src/main/kotlin/dev/vality/rateboss/config/properties/KafkaCustomProperties.kt b/src/main/kotlin/dev/vality/rateboss/config/properties/KafkaCustomProperties.kt
index 2707a42..28b6e99 100644
--- a/src/main/kotlin/dev/vality/rateboss/config/properties/KafkaCustomProperties.kt
+++ b/src/main/kotlin/dev/vality/rateboss/config/properties/KafkaCustomProperties.kt
@@ -1,26 +1,24 @@
package dev.vality.rateboss.config.properties
import org.springframework.boot.context.properties.ConfigurationProperties
-import org.springframework.boot.context.properties.ConstructorBinding
-@ConstructorBinding
@ConfigurationProperties(prefix = "kafka")
data class KafkaCustomProperties(
val producer: KafkaProducerProperties,
- val topic: KafkaTopicProperties
+ val topic: KafkaTopicProperties,
)
data class KafkaProducerProperties(
val maxRetries: Int,
val retryBackoffMs: Long,
val batchSize: Int,
- val deliveryTimeoutMs: Int
+ val deliveryTimeoutMs: Int,
)
data class KafkaTopicProperties(
- val producer: KafkaTopicProducerProperties
+ val producer: KafkaTopicProducerProperties,
)
data class KafkaTopicProducerProperties(
- val exchangeTopic: String
+ val exchangeTopic: String,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/config/properties/RatesProperties.kt b/src/main/kotlin/dev/vality/rateboss/config/properties/RatesProperties.kt
index dbfa0b6..9264c98 100644
--- a/src/main/kotlin/dev/vality/rateboss/config/properties/RatesProperties.kt
+++ b/src/main/kotlin/dev/vality/rateboss/config/properties/RatesProperties.kt
@@ -1,42 +1,40 @@
package dev.vality.rateboss.config.properties
import org.springframework.boot.context.properties.ConfigurationProperties
-import org.springframework.boot.context.properties.ConstructorBinding
import org.springframework.validation.annotation.Validated
import java.time.ZoneId
@Validated
-@ConstructorBinding
@ConfigurationProperties(prefix = "rates")
data class RatesProperties(
val fixerJob: JobDescription,
val cbrJob: JobDescription,
- val source: RatesSourceProperties
+ val source: RatesSourceProperties,
)
data class JobDescription(
val jobCron: String,
val jobKey: String,
val jobTriggerName: String,
- val currencies: List
+ val currencies: List,
)
data class CurrencyProperties(
val symbolCode: String,
- val exponent: Int
+ val exponent: Int,
)
data class RatesSourceProperties(
val fixer: FixerProperties,
- val cbr: CbrProperties
+ val cbr: CbrProperties,
)
data class FixerProperties(
val rootUrl: String,
- val apiKey: String
+ val apiKey: String,
)
data class CbrProperties(
val rootUrl: String,
- val timeZone: ZoneId
+ val timeZone: ZoneId,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/converter/ExRateConverter.kt b/src/main/kotlin/dev/vality/rateboss/converter/ExRateConverter.kt
index 7d6a56b..b7bb481 100644
--- a/src/main/kotlin/dev/vality/rateboss/converter/ExRateConverter.kt
+++ b/src/main/kotlin/dev/vality/rateboss/converter/ExRateConverter.kt
@@ -13,19 +13,19 @@ private const val DEFAULT_EXPONENT = 2
@Component
class ExRateConverter {
-
fun convert(
baseCurrencySymbolCode: String,
baseCurrencyExponent: Short,
exchangeRateMapEntry: Map.Entry,
exchangeRateTimestamp: Long,
- sourceId: String
+ sourceId: String,
): ExRate {
- val exponent = try {
- Monetary.getCurrency(exchangeRateMapEntry.key).defaultFractionDigits
- } catch (e: Exception) {
- DEFAULT_EXPONENT
- }
+ val exponent =
+ try {
+ Monetary.getCurrency(exchangeRateMapEntry.key).defaultFractionDigits
+ } catch (e: Exception) {
+ DEFAULT_EXPONENT
+ }
return ExRate().apply {
destinationCurrencySymbolicCode = baseCurrencySymbolCode
destinationCurrencyExponent = baseCurrencyExponent
diff --git a/src/main/kotlin/dev/vality/rateboss/converter/GetCurrencyExchangeRateResultConverter.kt b/src/main/kotlin/dev/vality/rateboss/converter/GetCurrencyExchangeRateResultConverter.kt
index 37be136..bceb8eb 100644
--- a/src/main/kotlin/dev/vality/rateboss/converter/GetCurrencyExchangeRateResultConverter.kt
+++ b/src/main/kotlin/dev/vality/rateboss/converter/GetCurrencyExchangeRateResultConverter.kt
@@ -10,11 +10,8 @@ import java.time.format.DateTimeFormatter
@Component
class GetCurrencyExchangeRateResultConverter {
-
- fun convert(
- exchangeRateData: ExchangeRateData
- ): GetCurrencyExchangeRateResult {
- return GetCurrencyExchangeRateResult().apply {
+ fun convert(exchangeRateData: ExchangeRateData): GetCurrencyExchangeRateResult =
+ GetCurrencyExchangeRateResult().apply {
currencyData = CurrencyData()
currencyData.sourceCurrency = exchangeRateData.sourceCurrencySymbolicCode
currencyData.destinationCurrency = exchangeRateData.destinationCurrencySymbolicCode
@@ -23,7 +20,6 @@ class GetCurrencyExchangeRateResultConverter {
exchange_rate.q = exchangeRateData.rationalQ
timestamp = exchangeRateData.rateTimestamp.format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))
}
- }
}
class Constants {
diff --git a/src/main/kotlin/dev/vality/rateboss/converter/TimestampExchangeRateRequestConverter.kt b/src/main/kotlin/dev/vality/rateboss/converter/TimestampExchangeRateRequestConverter.kt
index 919f66d..30f4013 100644
--- a/src/main/kotlin/dev/vality/rateboss/converter/TimestampExchangeRateRequestConverter.kt
+++ b/src/main/kotlin/dev/vality/rateboss/converter/TimestampExchangeRateRequestConverter.kt
@@ -9,19 +9,18 @@ import java.time.format.DateTimeFormatter
@Component
class TimestampExchangeRateRequestConverter {
-
fun convert(
conversionRequest: ConversionRequest,
- sourceId: String
- ): TimestampExchangeRateRequest {
- return TimestampExchangeRateRequest(
+ sourceId: String,
+ ): TimestampExchangeRateRequest =
+ TimestampExchangeRateRequest(
sourceCurrency = conversionRequest.source,
destinationCurrency = conversionRequest.destination,
source = sourceId,
- rateTimestamp = LocalDateTime.parse(
- conversionRequest.datetime,
- DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)
- )
+ rateTimestamp =
+ LocalDateTime.parse(
+ conversionRequest.datetime,
+ DateTimeFormatter.ofPattern(DATE_TIME_FORMAT),
+ ),
)
- }
}
diff --git a/src/main/kotlin/dev/vality/rateboss/dao/ExRateDao.kt b/src/main/kotlin/dev/vality/rateboss/dao/ExRateDao.kt
index b3dfbcd..583ba5d 100644
--- a/src/main/kotlin/dev/vality/rateboss/dao/ExRateDao.kt
+++ b/src/main/kotlin/dev/vality/rateboss/dao/ExRateDao.kt
@@ -4,10 +4,12 @@ import dev.vality.rateboss.dao.domain.tables.pojos.ExRate
import dev.vality.rateboss.service.model.TimestampExchangeRateRequest
interface ExRateDao {
-
fun saveBatch(entities: List)
- fun getRecentBySymbolicCodes(sourceCode: String, destinationCode: String): ExRate?
+ fun getRecentBySymbolicCodes(
+ sourceCode: String,
+ destinationCode: String,
+ ): ExRate?
fun getByCodesAndTimestamp(request: TimestampExchangeRateRequest): ExRate?
}
diff --git a/src/main/kotlin/dev/vality/rateboss/dao/ExRateDaoImpl.kt b/src/main/kotlin/dev/vality/rateboss/dao/ExRateDaoImpl.kt
index da3ae07..7fe90eb 100644
--- a/src/main/kotlin/dev/vality/rateboss/dao/ExRateDaoImpl.kt
+++ b/src/main/kotlin/dev/vality/rateboss/dao/ExRateDaoImpl.kt
@@ -10,44 +10,51 @@ import org.springframework.stereotype.Repository
@Repository
class ExRateDaoImpl(
- private val dsl: DSLContext
+ private val dsl: DSLContext,
) : ExRateDao {
override fun saveBatch(entities: List) {
val t = EX_RATE
- dsl.batch(
- entities.map { entity ->
- dsl.insertInto(
- t,
- t.SOURCE_CURRENCY_SYMBOLIC_CODE,
- t.SOURCE_CURRENCY_EXPONENT,
- t.DESTINATION_CURRENCY_SYMBOLIC_CODE,
- t.DESTINATION_CURRENCY_EXPONENT,
- t.RATIONAL_P,
- t.RATIONAL_Q,
- t.RATE_TIMESTAMP,
- t.SOURCE,
- t.REQUEST_DATE
- ).values(
- entity.sourceCurrencySymbolicCode,
- entity.sourceCurrencyExponent,
- entity.destinationCurrencySymbolicCode,
- entity.destinationCurrencyExponent,
- entity.rationalP,
- entity.rationalQ,
- entity.rateTimestamp,
- entity.source,
- entity.requestDate
- )
- }
- ).execute()
+ dsl
+ .batch(
+ entities.map { entity ->
+ dsl
+ .insertInto(
+ t,
+ t.SOURCE_CURRENCY_SYMBOLIC_CODE,
+ t.SOURCE_CURRENCY_EXPONENT,
+ t.DESTINATION_CURRENCY_SYMBOLIC_CODE,
+ t.DESTINATION_CURRENCY_EXPONENT,
+ t.RATIONAL_P,
+ t.RATIONAL_Q,
+ t.RATE_TIMESTAMP,
+ t.SOURCE,
+ t.REQUEST_DATE,
+ ).values(
+ entity.sourceCurrencySymbolicCode,
+ entity.sourceCurrencyExponent,
+ entity.destinationCurrencySymbolicCode,
+ entity.destinationCurrencyExponent,
+ entity.rationalP,
+ entity.rationalQ,
+ entity.rateTimestamp,
+ entity.source,
+ entity.requestDate,
+ )
+ },
+ ).execute()
}
- override fun getRecentBySymbolicCodes(sourceCode: String, destinationCode: String): ExRate? {
+ override fun getRecentBySymbolicCodes(
+ sourceCode: String,
+ destinationCode: String,
+ ): ExRate? {
val t = EX_RATE
- return dsl.selectFrom(t)
+ return dsl
+ .selectFrom(t)
.where(
- t.DESTINATION_CURRENCY_SYMBOLIC_CODE.eq(destinationCode)
- .and(t.SOURCE_CURRENCY_SYMBOLIC_CODE.eq(sourceCode))
+ t.DESTINATION_CURRENCY_SYMBOLIC_CODE
+ .eq(destinationCode)
+ .and(t.SOURCE_CURRENCY_SYMBOLIC_CODE.eq(sourceCode)),
).orderBy(t.RATE_TIMESTAMP.desc())
.limit(1)
.fetchOneInto(ExRate::class.java)
@@ -56,12 +63,14 @@ class ExRateDaoImpl(
override fun getByCodesAndTimestamp(request: TimestampExchangeRateRequest): ExRate? {
val t = EX_RATE
val targetRateDate = request.rateTimestamp.toLocalDate()
- return dsl.selectFrom(t)
+ return dsl
+ .selectFrom(t)
.where(
- t.DESTINATION_CURRENCY_SYMBOLIC_CODE.eq(request.destinationCurrency)
+ t.DESTINATION_CURRENCY_SYMBOLIC_CODE
+ .eq(request.destinationCurrency)
.and(t.SOURCE_CURRENCY_SYMBOLIC_CODE.eq(request.sourceCurrency))
.and(t.SOURCE.eq(request.source))
- .and(DSL.cast(t.RATE_TIMESTAMP, SQLDataType.LOCALDATE).eq(targetRateDate))
+ .and(DSL.cast(t.RATE_TIMESTAMP, SQLDataType.LOCALDATE).eq(targetRateDate)),
).orderBy(t.RATE_TIMESTAMP.desc())
.limit(1)
.fetchOneInto(ExRate::class.java)
diff --git a/src/main/kotlin/dev/vality/rateboss/extensions/BigDecimalExtension.kt b/src/main/kotlin/dev/vality/rateboss/extensions/BigDecimalExtension.kt
index a4f95ec..5846e8d 100644
--- a/src/main/kotlin/dev/vality/rateboss/extensions/BigDecimalExtension.kt
+++ b/src/main/kotlin/dev/vality/rateboss/extensions/BigDecimalExtension.kt
@@ -5,9 +5,12 @@ import java.math.BigInteger
fun BigDecimal.toRational(): Rational {
val denominator: BigInteger = if (this.scale() > 0) BigInteger.TEN.pow(this.scale()) else BigInteger.ONE
- val numerator: BigInteger = this.remainder(BigDecimal.ONE)
- .movePointRight(this.scale()).toBigInteger()
- .add(this.toBigInteger().multiply(denominator))
+ val numerator: BigInteger =
+ this
+ .remainder(BigDecimal.ONE)
+ .movePointRight(this.scale())
+ .toBigInteger()
+ .add(this.toBigInteger().multiply(denominator))
if (numerator > BigInteger.valueOf(Long.MAX_VALUE)) {
throw ArithmeticException("Numerator out of long range: $numerator")
@@ -21,5 +24,5 @@ fun BigDecimal.toRational(): Rational {
data class Rational(
val numerator: Long,
- val denominator: Long
+ val denominator: Long,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/extensions/JobExecutionContextExtension.kt b/src/main/kotlin/dev/vality/rateboss/extensions/JobExecutionContextExtension.kt
index 5406f8d..d5eb2fc 100644
--- a/src/main/kotlin/dev/vality/rateboss/extensions/JobExecutionContextExtension.kt
+++ b/src/main/kotlin/dev/vality/rateboss/extensions/JobExecutionContextExtension.kt
@@ -4,7 +4,6 @@ import org.quartz.JobExecutionContext
import org.quartz.JobExecutionException
import org.springframework.context.ApplicationContext
-fun JobExecutionContext.getApplicationContext(): ApplicationContext {
- return this.scheduler.context["applicationContext"] as? ApplicationContext
+fun JobExecutionContext.getApplicationContext(): ApplicationContext =
+ this.scheduler.context["applicationContext"] as? ApplicationContext
?: throw JobExecutionException("No application context available in scheduler context")
-}
diff --git a/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberJob.kt b/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberJob.kt
index 0957014..cf9070d 100644
--- a/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberJob.kt
+++ b/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberJob.kt
@@ -11,23 +11,23 @@ import org.springframework.scheduling.quartz.QuartzJobBean
private val log = KotlinLogging.logger {}
abstract class AbstractExchangeGrabberJob : QuartzJobBean() {
-
fun saveExchangeRates(
applicationContext: ApplicationContext,
currencySymbolCode: String,
currencyExponent: Int,
exchangeRates: ExchangeRates,
- sourceId: String
+ sourceId: String,
) {
try {
val exchangeDaoService = applicationContext.getBean(ExchangeDaoService::class.java)
log.info { "Save exchange rates for currency=$currencySymbolCode, sourceId=$sourceId" }
- val exchangeRatesData = ExchangeRatesData(
- destinationCurrencySymbolicCode = currencySymbolCode,
- destinationCurrencyExponent = currencyExponent.toShort(),
- exchangeRates = exchangeRates,
- sourceId = sourceId
- )
+ val exchangeRatesData =
+ ExchangeRatesData(
+ destinationCurrencySymbolicCode = currencySymbolCode,
+ destinationCurrencyExponent = currencyExponent.toShort(),
+ exchangeRates = exchangeRates,
+ sourceId = sourceId,
+ )
exchangeDaoService.saveExchangeRates(exchangeRatesData)
} catch (e: Exception) {
log.error("Couldn't save exchange rates for currency={} ", currencySymbolCode, e)
@@ -38,7 +38,7 @@ abstract class AbstractExchangeGrabberJob : QuartzJobBean() {
applicationContext: ApplicationContext,
currencySymbolCode: String,
currencyExponent: Int,
- exchangeRates: ExchangeRates
+ exchangeRates: ExchangeRates,
) {
val exchangeEventService = applicationContext.getBean(ExchangeEventService::class.java)
log.info { "Send exchange rates for currency=$currencySymbolCode" }
diff --git a/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberMasterJob.kt b/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberMasterJob.kt
index 3a8086f..e598955 100644
--- a/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberMasterJob.kt
+++ b/src/main/kotlin/dev/vality/rateboss/job/AbstractExchangeGrabberMasterJob.kt
@@ -10,27 +10,30 @@ import java.util.*
private val log = KotlinLogging.logger {}
abstract class AbstractExchangeGrabberMasterJob : QuartzJobBean() {
-
fun launchJob(
currencies: List,
schedulerFactoryBean: Scheduler,
jobType: Class,
- jobName: String
+ jobName: String,
) {
for (currency in currencies) {
val jobIdentity = "$jobName-${currency.symbolCode}-currency-job"
- val jobDetail = JobBuilder.newJob(jobType)
- .withIdentity(jobIdentity)
- .build()
- val triggerFactoryBean = SimpleTriggerFactoryBean().apply {
- setPriority(Int.MAX_VALUE)
- setName(jobIdentity)
- setStartTime(Date())
- setRepeatInterval(0L)
- setRepeatCount(0)
- setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW)
- afterPropertiesSet()
- }.getObject()
+ val jobDetail =
+ JobBuilder
+ .newJob(jobType)
+ .withIdentity(jobIdentity)
+ .build()
+ val triggerFactoryBean =
+ SimpleTriggerFactoryBean()
+ .apply {
+ setPriority(Int.MAX_VALUE)
+ setName(jobIdentity)
+ setStartTime(Date())
+ setRepeatInterval(0L)
+ setRepeatCount(0)
+ setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW)
+ afterPropertiesSet()
+ }.getObject()
jobDetail.jobDataMap["currencySymbolCode"] = currency.symbolCode
jobDetail.jobDataMap["currencyExponent"] = currency.exponent
try {
diff --git a/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJob.kt b/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJob.kt
index f66dbb9..3ddda09 100644
--- a/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJob.kt
+++ b/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJob.kt
@@ -13,7 +13,6 @@ import org.springframework.retry.support.RetryTemplate
private val log = KotlinLogging.logger {}
class CbrExchangeGrabberJob : AbstractExchangeGrabberJob() {
-
override fun executeInternal(context: JobExecutionContext) {
val applicationContext = context.getApplicationContext()
val currencySymbolCode = context.jobDetail.jobDataMap["currencySymbolCode"] as String
@@ -28,12 +27,13 @@ class CbrExchangeGrabberJob : AbstractExchangeGrabberJob() {
private fun getExchangeRates(
applicationContext: ApplicationContext,
exchangeRateSource: ExchangeRateSource,
- currencySymbolCode: String
+ currencySymbolCode: String,
): ExchangeRates {
val retryTemplate = applicationContext.getBean(RetryTemplate::class.java)
- val exchangeRates = retryTemplate.execute {
- exchangeRateSource.getExchangeRate(currencySymbolCode)
- }
+ val exchangeRates =
+ retryTemplate.execute {
+ exchangeRateSource.getExchangeRate(currencySymbolCode)
+ }
return exchangeRates
}
}
diff --git a/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberMasterJob.kt b/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberMasterJob.kt
index c99d39a..528b907 100644
--- a/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberMasterJob.kt
+++ b/src/main/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberMasterJob.kt
@@ -6,7 +6,6 @@ import org.quartz.JobExecutionContext
import org.quartz.Scheduler
class CbrExchangeGrabberMasterJob : AbstractExchangeGrabberMasterJob() {
-
override fun executeInternal(context: JobExecutionContext) {
val applicationContext = context.getApplicationContext()
val ratesProperties = applicationContext.getBean(RatesProperties::class.java)
@@ -15,7 +14,5 @@ class CbrExchangeGrabberMasterJob : AbstractExchangeGrabberMasterJob() {
launchJob(currencies, schedulerFactoryBean, CbrExchangeGrabberJob::class.java, getJobName())
}
- override fun getJobName(): String {
- return "cbrJob"
- }
+ override fun getJobName(): String = "cbrJob"
}
diff --git a/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJob.kt b/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJob.kt
index 12a7b9c..6a8e218 100644
--- a/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJob.kt
+++ b/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJob.kt
@@ -13,7 +13,6 @@ import org.springframework.retry.support.RetryTemplate
private val log = KotlinLogging.logger {}
class FixerExchangeGrabberJob : AbstractExchangeGrabberJob() {
-
override fun executeInternal(context: JobExecutionContext) {
val applicationContext = context.getApplicationContext()
val currencySymbolCode = context.jobDetail.jobDataMap["currencySymbolCode"] as String
@@ -29,12 +28,13 @@ class FixerExchangeGrabberJob : AbstractExchangeGrabberJob() {
private fun getExchangeRates(
applicationContext: ApplicationContext,
exchangeRateSource: ExchangeRateSource,
- currencySymbolCode: String
+ currencySymbolCode: String,
): ExchangeRates {
val retryTemplate = applicationContext.getBean(RetryTemplate::class.java)
- val exchangeRates = retryTemplate.execute {
- exchangeRateSource.getExchangeRate(currencySymbolCode)
- }
+ val exchangeRates =
+ retryTemplate.execute {
+ exchangeRateSource.getExchangeRate(currencySymbolCode)
+ }
return exchangeRates
}
}
diff --git a/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberMasterJob.kt b/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberMasterJob.kt
index bb7773a..13e1cba 100644
--- a/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberMasterJob.kt
+++ b/src/main/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberMasterJob.kt
@@ -9,7 +9,6 @@ import org.quartz.Scheduler
private val log = KotlinLogging.logger {}
class FixerExchangeGrabberMasterJob : AbstractExchangeGrabberMasterJob() {
-
override fun executeInternal(context: JobExecutionContext) {
val applicationContext = context.getApplicationContext()
val ratesProperties = applicationContext.getBean(RatesProperties::class.java)
@@ -18,7 +17,5 @@ class FixerExchangeGrabberMasterJob : AbstractExchangeGrabberMasterJob() {
launchJob(currencies, schedulerFactoryBean, FixerExchangeGrabberJob::class.java, getJobName())
}
- override fun getJobName(): String {
- return "fixerJob"
- }
+ override fun getJobName(): String = "fixerJob"
}
diff --git a/src/main/kotlin/dev/vality/rateboss/service/ConversionService.kt b/src/main/kotlin/dev/vality/rateboss/service/ConversionService.kt
index 992d4a9..5c29157 100644
--- a/src/main/kotlin/dev/vality/rateboss/service/ConversionService.kt
+++ b/src/main/kotlin/dev/vality/rateboss/service/ConversionService.kt
@@ -5,9 +5,10 @@ import org.springframework.stereotype.Service
@Service
class ConversionService {
-
- fun convertAmount(amount: Long, rate: BigFraction): BigFraction {
- return BigFraction(amount)
+ fun convertAmount(
+ amount: Long,
+ rate: BigFraction,
+ ): BigFraction =
+ BigFraction(amount)
.multiply(BigFraction(rate.numerator, rate.denominator))
- }
}
diff --git a/src/main/kotlin/dev/vality/rateboss/service/ExRateServiceHandler.kt b/src/main/kotlin/dev/vality/rateboss/service/ExRateServiceHandler.kt
index c4e46ac..c26f304 100644
--- a/src/main/kotlin/dev/vality/rateboss/service/ExRateServiceHandler.kt
+++ b/src/main/kotlin/dev/vality/rateboss/service/ExRateServiceHandler.kt
@@ -14,30 +14,35 @@ class ExRateServiceHandler(
private val exRateDaoService: ExchangeDaoService,
private val getCurrencyExchangeRateResultConverter: GetCurrencyExchangeRateResultConverter,
private val conversionService: ConversionService,
- private val timestampExchangeRateRequestConverter: TimestampExchangeRateRequestConverter
+ private val timestampExchangeRateRequestConverter: TimestampExchangeRateRequestConverter,
) : ExchangeRateServiceSrv.Iface {
-
override fun getExchangeRateData(request: GetCurrencyExchangeRateRequest): GetCurrencyExchangeRateResult {
log.info("Get getExchangeRateData request with body: {} ", request)
- val exchangeRateData = exRateDaoService.getRecentExchangeRateBySymbolicCodes(
- request.currencyData.sourceCurrency,
- request.currencyData.destinationCurrency
- )
- val result = exchangeRateData?.let {
- getCurrencyExchangeRateResultConverter.convert(exchangeRateData)
- } ?: throw ExRateNotFound()
+ val exchangeRateData =
+ exRateDaoService.getRecentExchangeRateBySymbolicCodes(
+ request.currencyData.sourceCurrency,
+ request.currencyData.destinationCurrency,
+ )
+ val result =
+ exchangeRateData?.let {
+ getCurrencyExchangeRateResultConverter.convert(exchangeRateData)
+ } ?: throw ExRateNotFound()
log.info("Result getExchangeRateData with body: {}", result)
return result
}
- override fun getConvertedAmount(sourceId: String, conversionRequest: ConversionRequest): Rational {
+ override fun getConvertedAmount(
+ sourceId: String,
+ conversionRequest: ConversionRequest,
+ ): Rational {
log.info("Get getConvertedAmount request for source: {} with body: {} ", sourceId, conversionRequest)
val exchangeTimestampRequest = timestampExchangeRateRequestConverter.convert(conversionRequest, sourceId)
val exRateByTimestamp = exRateDaoService.getExchangeRateByTimestamp(exchangeTimestampRequest)
- val result = exRateByTimestamp?.let {
- val convertedAmount = conversionService.convertAmount(conversionRequest.amount, exRateByTimestamp)
- Rational(convertedAmount.numeratorAsLong, convertedAmount.denominatorAsLong)
- } ?: throw ExRateNotFound()
+ val result =
+ exRateByTimestamp?.let {
+ val convertedAmount = conversionService.convertAmount(conversionRequest.amount, exRateByTimestamp)
+ Rational(convertedAmount.numeratorAsLong, convertedAmount.denominatorAsLong)
+ } ?: throw ExRateNotFound()
log.info("Result getConvertedAmount with body: {} ", result)
return result
}
diff --git a/src/main/kotlin/dev/vality/rateboss/service/ExchangeDaoService.kt b/src/main/kotlin/dev/vality/rateboss/service/ExchangeDaoService.kt
index f485751..452bbce 100644
--- a/src/main/kotlin/dev/vality/rateboss/service/ExchangeDaoService.kt
+++ b/src/main/kotlin/dev/vality/rateboss/service/ExchangeDaoService.kt
@@ -14,28 +14,30 @@ private val log = KotlinLogging.logger {}
@Service
class ExchangeDaoService(
private val exRateDao: ExRateDao,
- private val exRateConverter: ExRateConverter
+ private val exRateConverter: ExRateConverter,
) {
-
- fun saveExchangeRates(
- exchangeRatesData: ExchangeRatesData
- ) {
- val exRates = exchangeRatesData.exchangeRates.rates.map { exchangeRatesMap ->
- val exRate = exRateConverter.convert(
- exchangeRatesData.destinationCurrencySymbolicCode,
- exchangeRatesData.destinationCurrencyExponent,
- exchangeRatesMap,
- exchangeRatesData.exchangeRates.timestamp,
- exchangeRatesData.sourceId
- )
- exRate
- }
+ fun saveExchangeRates(exchangeRatesData: ExchangeRatesData) {
+ val exRates =
+ exchangeRatesData.exchangeRates.rates.map { exchangeRatesMap ->
+ val exRate =
+ exRateConverter.convert(
+ exchangeRatesData.destinationCurrencySymbolicCode,
+ exchangeRatesData.destinationCurrencyExponent,
+ exchangeRatesMap,
+ exchangeRatesData.exchangeRates.timestamp,
+ exchangeRatesData.sourceId,
+ )
+ exRate
+ }
log.debug("Try to save exRate batch {}", exRates)
exRateDao.saveBatch(exRates)
log.info("Successfully save exRate batch with size: {}", exRates.size)
}
- fun getRecentExchangeRateBySymbolicCodes(sourceCode: String, destinationCode: String): ExchangeRateData? {
+ fun getRecentExchangeRateBySymbolicCodes(
+ sourceCode: String,
+ destinationCode: String,
+ ): ExchangeRateData? {
val exRate = exRateDao.getRecentBySymbolicCodes(sourceCode, destinationCode)
return exRate?.let {
ExchangeRateData(
@@ -44,7 +46,7 @@ class ExchangeDaoService(
rationalP = it.rationalP,
rationalQ = it.rationalQ,
rateTimestamp = it.rateTimestamp,
- source = it.source
+ source = it.source,
)
}
}
diff --git a/src/main/kotlin/dev/vality/rateboss/service/ExchangeEventService.kt b/src/main/kotlin/dev/vality/rateboss/service/ExchangeEventService.kt
index be3e8c2..4951ea2 100644
--- a/src/main/kotlin/dev/vality/rateboss/service/ExchangeEventService.kt
+++ b/src/main/kotlin/dev/vality/rateboss/service/ExchangeEventService.kt
@@ -23,40 +23,49 @@ private val log = KotlinLogging.logger {}
@Service
class ExchangeEventService(
- private val kafkaTemplate: KafkaTemplate
+ private val kafkaTemplate: KafkaTemplate,
) {
-
@Value("\${kafka.topic.producer.exchangeTopic}")
lateinit var topicName: String
fun sendExchangeRates(
baseCurrencySymbolCode: String,
baseCurrencyExponent: Short,
- exchangeRates: ExchangeRates
+ exchangeRates: ExchangeRates,
) {
- val currencyEvents = exchangeRates.rates.map { exchangeRatesMap ->
- val eventId = UUID.randomUUID().toString()
- val eventTime = TypeUtil.temporalToString(LocalDateTime.now(), ZoneOffset.UTC)
- val payload = buildCurrencyExchangeRatePayload(
- baseCurrencySymbolCode,
- baseCurrencyExponent,
- exchangeRatesMap,
- exchangeRates.timestamp
- )
- CurrencyEvent(eventId, eventTime, payload)
- }
+ val currencyEvents =
+ exchangeRates.rates.map { exchangeRatesMap ->
+ val eventId = UUID.randomUUID().toString()
+ val eventTime = TypeUtil.temporalToString(LocalDateTime.now(), ZoneOffset.UTC)
+ val payload =
+ buildCurrencyExchangeRatePayload(
+ baseCurrencySymbolCode,
+ baseCurrencyExponent,
+ exchangeRatesMap,
+ exchangeRates.timestamp,
+ )
+ CurrencyEvent(eventId, eventTime, payload)
+ }
for (currencyEvent in currencyEvents) {
val producerRecord = ProducerRecord(topicName, currencyEvent.eventId, currencyEvent)
- kafkaTemplate.send(producerRecord).addCallback(
- { result ->
- log.info {
- "Successfully send currency event. Topic=" + result?.recordMetadata?.topic() + ";" +
- " Offset=" + result?.recordMetadata?.offset() + ";" +
- " Partition=" + result?.recordMetadata?.partition()
+ kafkaTemplate
+ .send(producerRecord)
+ .thenAccept(
+ { result ->
+ log.info {
+ "Successfully send currency event. Topic=" + result?.recordMetadata?.topic() + ";" +
+ " Offset=" + result?.recordMetadata?.offset() + ";" +
+ " Partition=" + result?.recordMetadata?.partition()
+ }
}
- },
- { log.error(it.cause) { "Failed to send event. Topic=${producerRecord.topic()}; Partition=${producerRecord.partition()}" } }
- )
+ ).exceptionally(
+ { err ->
+ log.error(
+ err.cause
+ ) { "Failed to send event. Topic=${producerRecord.topic()}; Partition=${producerRecord.partition()}" }
+ null
+ }
+ )
}
}
@@ -64,30 +73,26 @@ class ExchangeEventService(
baseCurrencySymbolCode: String,
baseCurrencyExponent: Short,
exchangeRateMap: Map.Entry,
- exchangeRateTimestamp: Long
- ): CurrencyEventPayload? {
- return CurrencyEventPayload.exchange_rate(
+ exchangeRateTimestamp: Long,
+ ): CurrencyEventPayload? =
+ CurrencyEventPayload.exchange_rate(
CurrencyExchangeRate()
.setSourceCurrency(
Currency(
baseCurrencySymbolCode,
- baseCurrencyExponent
- )
- )
- .setDestinationCurrency(
+ baseCurrencyExponent,
+ ),
+ ).setDestinationCurrency(
Currency(
exchangeRateMap.key,
- exchangeRateMap.value.scale().toShort()
- )
- )
- .setExchangeRate(
+ exchangeRateMap.value.scale().toShort(),
+ ),
+ ).setExchangeRate(
Rational().apply {
val rational = exchangeRateMap.value.toRational()
p = rational.numerator
q = rational.denominator
- }
- )
- .setTimestamp(TypeUtil.temporalToString(Instant.ofEpochSecond(exchangeRateTimestamp)))
+ },
+ ).setTimestamp(TypeUtil.temporalToString(Instant.ofEpochSecond(exchangeRateTimestamp))),
)
- }
}
diff --git a/src/main/kotlin/dev/vality/rateboss/service/model/ExchangeRateData.kt b/src/main/kotlin/dev/vality/rateboss/service/model/ExchangeRateData.kt
index 531a709..9ec1bbd 100644
--- a/src/main/kotlin/dev/vality/rateboss/service/model/ExchangeRateData.kt
+++ b/src/main/kotlin/dev/vality/rateboss/service/model/ExchangeRateData.kt
@@ -8,5 +8,5 @@ data class ExchangeRateData(
val rationalP: Long,
val rationalQ: Long,
val rateTimestamp: LocalDateTime,
- val source: String
+ val source: String,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/service/model/TimestampExchangeRateRequest.kt b/src/main/kotlin/dev/vality/rateboss/service/model/TimestampExchangeRateRequest.kt
index 9dcf1d8..aec139b 100644
--- a/src/main/kotlin/dev/vality/rateboss/service/model/TimestampExchangeRateRequest.kt
+++ b/src/main/kotlin/dev/vality/rateboss/service/model/TimestampExchangeRateRequest.kt
@@ -6,5 +6,5 @@ data class TimestampExchangeRateRequest(
val sourceCurrency: String,
val destinationCurrency: String,
val rateTimestamp: LocalDateTime,
- val source: String
+ val source: String,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/servlet/ExRateServlet.kt b/src/main/kotlin/dev/vality/rateboss/servlet/ExRateServlet.kt
index a441bcd..84831ab 100644
--- a/src/main/kotlin/dev/vality/rateboss/servlet/ExRateServlet.kt
+++ b/src/main/kotlin/dev/vality/rateboss/servlet/ExRateServlet.kt
@@ -2,14 +2,13 @@ package dev.vality.rateboss.servlet
import dev.vality.exrates.service.ExchangeRateServiceSrv
import dev.vality.woody.thrift.impl.http.THServiceBuilder
-import javax.servlet.*
-import javax.servlet.annotation.WebServlet
+import jakarta.servlet.*
+import jakarta.servlet.annotation.WebServlet
@WebServlet("/ex-rate")
class ExRateServlet(
- private val serverHandler: ExchangeRateServiceSrv.Iface
+ private val serverHandler: ExchangeRateServiceSrv.Iface,
) : GenericServlet() {
-
private lateinit var servlet: Servlet
override fun init(config: ServletConfig) {
@@ -17,7 +16,10 @@ class ExRateServlet(
servlet = THServiceBuilder().build(ExchangeRateServiceSrv.Iface::class.java, serverHandler)
}
- override fun service(request: ServletRequest, response: ServletResponse) {
+ override fun service(
+ request: ServletRequest,
+ response: ServletResponse,
+ ) {
servlet.service(request, response)
}
}
diff --git a/src/main/kotlin/dev/vality/rateboss/source/ExchangeRateSourceException.kt b/src/main/kotlin/dev/vality/rateboss/source/ExchangeRateSourceException.kt
index eeb1780..467a317 100644
--- a/src/main/kotlin/dev/vality/rateboss/source/ExchangeRateSourceException.kt
+++ b/src/main/kotlin/dev/vality/rateboss/source/ExchangeRateSourceException.kt
@@ -2,5 +2,5 @@ package dev.vality.rateboss.source
class ExchangeRateSourceException(
msg: String,
- cause: Throwable? = null
+ cause: Throwable? = null,
) : RuntimeException(msg, cause)
diff --git a/src/main/kotlin/dev/vality/rateboss/source/impl/CbrExchangeRateSource.kt b/src/main/kotlin/dev/vality/rateboss/source/impl/CbrExchangeRateSource.kt
index d7cb575..d80b600 100644
--- a/src/main/kotlin/dev/vality/rateboss/source/impl/CbrExchangeRateSource.kt
+++ b/src/main/kotlin/dev/vality/rateboss/source/impl/CbrExchangeRateSource.kt
@@ -15,34 +15,33 @@ private val log = KotlinLogging.logger {}
@Component
class CbrExchangeRateSource(
- private val cbrApiClient: CbrApiClient
+ private val cbrApiClient: CbrApiClient,
) : ExchangeRateSource {
-
override fun getExchangeRate(currencySymbolCode: String): ExchangeRates {
val time = Instant.now()
log.info("Trying to get exchange rates from cbr for currency={}, time={}", currencySymbolCode, time)
- val response = try {
- cbrApiClient.getExchangeRates(time)
- } catch (e: Exception) {
- throw ExchangeRateSourceException("Remote client exception", e)
- }
+ val response =
+ try {
+ cbrApiClient.getExchangeRates(time)
+ } catch (e: Exception) {
+ throw ExchangeRateSourceException("Remote client exception", e)
+ }
if (response.currencies.isNullOrEmpty()) {
throw ExchangeRateSourceException("Unsuccessful response from CbrApi")
}
- val rates: Map = response.currencies!!.associate {
- it.charCode!! to it.value!!.divide(it.nominal!!.toBigDecimal())
- }
+ val rates: Map =
+ response.currencies!!.associate {
+ it.charCode!! to it.value!!.divide(it.nominal!!.toBigDecimal())
+ }
val responseDate = response.date!!
val nextDayTimestamp = responseDate.plusDays(1).atStartOfDay().toEpochSecond(ZoneOffset.UTC)
log.info("Exchange rates from cbr have been retrieved, date=$responseDate, exchangeRates=$rates, targetTimestamp=$nextDayTimestamp")
return ExchangeRates(
rates = rates,
- timestamp = nextDayTimestamp
+ timestamp = nextDayTimestamp,
)
}
- override fun getSourceId(): String {
- return ExRateSources.CBR
- }
+ override fun getSourceId(): String = ExRateSources.CBR
}
diff --git a/src/main/kotlin/dev/vality/rateboss/source/impl/FixerExchangeRateSource.kt b/src/main/kotlin/dev/vality/rateboss/source/impl/FixerExchangeRateSource.kt
index 17dd25f..0056f74 100644
--- a/src/main/kotlin/dev/vality/rateboss/source/impl/FixerExchangeRateSource.kt
+++ b/src/main/kotlin/dev/vality/rateboss/source/impl/FixerExchangeRateSource.kt
@@ -9,26 +9,24 @@ import org.springframework.stereotype.Component
@Component
class FixerExchangeRateSource(
- private val fixerApiClient: FixerApiClient
+ private val fixerApiClient: FixerApiClient,
) : ExchangeRateSource {
-
override fun getExchangeRate(currencySymbolCode: String): ExchangeRates {
- val fixerLatestResponse = try {
- fixerApiClient.getLatest(currencySymbolCode)
- } catch (e: Exception) {
- throw ExchangeRateSourceException("Remote client exception", e)
- }
+ val fixerLatestResponse =
+ try {
+ fixerApiClient.getLatest(currencySymbolCode)
+ } catch (e: Exception) {
+ throw ExchangeRateSourceException("Remote client exception", e)
+ }
if (!fixerLatestResponse.success) {
throw ExchangeRateSourceException("Unsuccessful response from FixerApi")
}
return ExchangeRates(
rates = fixerLatestResponse.rates!!,
- timestamp = fixerLatestResponse.timestamp!!
+ timestamp = fixerLatestResponse.timestamp!!,
)
}
- override fun getSourceId(): String {
- return ExRateSources.FIXER
- }
+ override fun getSourceId(): String = ExRateSources.FIXER
}
diff --git a/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRates.kt b/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRates.kt
index 57c5b6c..f7f58f4 100644
--- a/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRates.kt
+++ b/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRates.kt
@@ -4,5 +4,5 @@ import java.math.BigDecimal
data class ExchangeRates(
val rates: Map,
- val timestamp: Long
+ val timestamp: Long,
)
diff --git a/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRatesData.kt b/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRatesData.kt
index 29dfa8d..44b0fb6 100644
--- a/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRatesData.kt
+++ b/src/main/kotlin/dev/vality/rateboss/source/model/ExchangeRatesData.kt
@@ -4,5 +4,5 @@ data class ExchangeRatesData(
val destinationCurrencySymbolicCode: String,
val destinationCurrencyExponent: Short,
val exchangeRates: ExchangeRates,
- val sourceId: String
+ val sourceId: String,
)
diff --git a/src/test/kotlin/dev/vality/rateboss/ContainerConfiguration.kt b/src/test/kotlin/dev/vality/rateboss/ContainerConfiguration.kt
index ab68dff..ae526b3 100644
--- a/src/test/kotlin/dev/vality/rateboss/ContainerConfiguration.kt
+++ b/src/test/kotlin/dev/vality/rateboss/ContainerConfiguration.kt
@@ -19,16 +19,18 @@ class ContainerConfiguration {
}
@JvmStatic
- val postgresql: PostgreSQLContainer = PostgreSQLContainer("postgres:14-alpine").apply {
- withDatabaseName("postgresql")
- withUsername("user")
- withPassword("password")
- }
+ val postgresql: PostgreSQLContainer =
+ PostgreSQLContainer("postgres:14-alpine").apply {
+ withDatabaseName("postgresql")
+ withUsername("user")
+ withPassword("password")
+ }
@JvmStatic
- val kafka: KafkaContainer = KafkaContainer(
- DockerImageName.parse("confluentinc/cp-kafka").withTag("7.0.1")
- ).withEmbeddedZookeeper()
+ val kafka: KafkaContainer =
+ KafkaContainer(
+ DockerImageName.parse("confluentinc/cp-kafka").withTag("7.0.1"),
+ ).withEmbeddedZookeeper()
@JvmStatic
@DynamicPropertySource
diff --git a/src/test/kotlin/dev/vality/rateboss/client/cbr/CbrApiClientTest.kt b/src/test/kotlin/dev/vality/rateboss/client/cbr/CbrApiClientTest.kt
index 7396566..e724b80 100644
--- a/src/test/kotlin/dev/vality/rateboss/client/cbr/CbrApiClientTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/client/cbr/CbrApiClientTest.kt
@@ -1,7 +1,8 @@
package dev.vality.rateboss.client.cbr
import dev.vality.rateboss.config.TestConfig
-import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.Assertions.assertNotNull
+import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
@@ -16,7 +17,6 @@ import java.time.Instant
@ContextConfiguration(classes = [CbrApiClient::class])
@Import(TestConfig::class)
class CbrApiClientTest {
-
@Autowired
lateinit var cbrApiClient: CbrApiClient
diff --git a/src/test/kotlin/dev/vality/rateboss/config/TestConfig.kt b/src/test/kotlin/dev/vality/rateboss/config/TestConfig.kt
index 8315efd..2d45379 100644
--- a/src/test/kotlin/dev/vality/rateboss/config/TestConfig.kt
+++ b/src/test/kotlin/dev/vality/rateboss/config/TestConfig.kt
@@ -8,29 +8,27 @@ import java.time.ZoneId
@TestConfiguration
class TestConfig {
-
@Bean
fun testRestTemplate() = RestTemplate()
@Bean
- fun testRatesProperties(): RatesProperties {
- return RatesProperties(
+ fun testRatesProperties(): RatesProperties =
+ RatesProperties(
JobDescription(
"fixer-cron",
"fixer-key",
"fixer-name",
- listOf(CurrencyProperties("USD", 2))
+ listOf(CurrencyProperties("USD", 2)),
),
JobDescription(
"cbr-cron",
"cbr-key",
"cbr-name",
- listOf(CurrencyProperties("RUB", 2))
+ listOf(CurrencyProperties("RUB", 2)),
),
RatesSourceProperties(
FixerProperties("url", "key"),
- CbrProperties("https://www.cbr.ru/scripts/XML_daily.asp", ZoneId.of("Europe/Moscow"))
- )
+ CbrProperties("https://www.cbr.ru/scripts/XML_daily.asp", ZoneId.of("Europe/Moscow")),
+ ),
)
- }
}
diff --git a/src/test/kotlin/dev/vality/rateboss/dao/ExRateDaoImplTest.kt b/src/test/kotlin/dev/vality/rateboss/dao/ExRateDaoImplTest.kt
index ccd6fb9..6215a5a 100644
--- a/src/test/kotlin/dev/vality/rateboss/dao/ExRateDaoImplTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/dao/ExRateDaoImplTest.kt
@@ -10,14 +10,13 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.quartz.Scheduler
import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.mock.mockito.MockBean
+import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.testcontainers.junit.jupiter.Testcontainers
import java.time.LocalDateTime
@Testcontainers
class ExRateDaoImplTest : ContainerConfiguration() {
-
- @MockBean
+ @MockitoBean
lateinit var scheduler: Scheduler
@Autowired
@@ -33,26 +32,28 @@ class ExRateDaoImplTest : ContainerConfiguration() {
@Test
fun saveBatchWithSameCodes() {
- val firstExRate = ExRate().apply {
- sourceCurrencySymbolicCode = "USD"
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = "UZS"
- destinationCurrencyExponent = 6
- rationalP = 11190000264
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now()
- source = "source"
- }
- val secondExRate = ExRate().apply {
- sourceCurrencySymbolicCode = "USD"
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = "UZS"
- destinationCurrencyExponent = 6
- rationalP = 1119000000
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now()
- source = "source"
- }
+ val firstExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = "USD"
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = "UZS"
+ destinationCurrencyExponent = 6
+ rationalP = 11190000264
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now()
+ source = "source"
+ }
+ val secondExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = "USD"
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = "UZS"
+ destinationCurrencyExponent = 6
+ rationalP = 1119000000
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now()
+ source = "source"
+ }
val entities = listOf(firstExRate, secondExRate)
exRateDao.saveBatch(entities)
@@ -65,26 +66,28 @@ class ExRateDaoImplTest : ContainerConfiguration() {
@Test
fun saveBatch() {
- val firstExRate = ExRate().apply {
- sourceCurrencySymbolicCode = "USD"
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = "UZS"
- destinationCurrencyExponent = 6
- rationalP = 11190000264
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now()
- source = "source"
- }
- val secondExRate = ExRate().apply {
- sourceCurrencySymbolicCode = "USD"
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = "RUB"
- destinationCurrencyExponent = 6
- rationalP = 1119000000
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now()
- source = "source"
- }
+ val firstExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = "USD"
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = "UZS"
+ destinationCurrencyExponent = 6
+ rationalP = 11190000264
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now()
+ source = "source"
+ }
+ val secondExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = "USD"
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = "RUB"
+ destinationCurrencyExponent = 6
+ rationalP = 1119000000
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now()
+ source = "source"
+ }
val entities = listOf(firstExRate, secondExRate)
exRateDao.saveBatch(entities)
@@ -97,27 +100,30 @@ class ExRateDaoImplTest : ContainerConfiguration() {
fun getRecentBySymbolicCodes() {
val sourceCurrency = "USD"
val destinationCurrency = "UZS"
- val oldExRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 6
- rationalP = 11190000264
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now().minusHours(1)
- source = "source"
- }
- val recentExRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 6
- rationalP = 1119000000
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now()
- source = "source"
- }
- dslContext.insertInto(EX_RATE)
+ val oldExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 6
+ rationalP = 11190000264
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now().minusHours(1)
+ source = "source"
+ }
+ val recentExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 6
+ rationalP = 1119000000
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now()
+ source = "source"
+ }
+ dslContext
+ .insertInto(EX_RATE)
.set(dslContext.newRecord(EX_RATE, oldExRate))
.newRecord()
.set(dslContext.newRecord(EX_RATE, recentExRate))
@@ -135,37 +141,41 @@ class ExRateDaoImplTest : ContainerConfiguration() {
val destinationCurrency = "USD"
val sourceCurrency = "UZS"
val sourceId = "source"
- val firstExRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 2
- rationalP = 11190000264
- rationalQ = 1000055
- rateTimestamp = LocalDateTime.now().minusDays(3)
- source = sourceId
- }
- val secondExRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 2
- rationalP = 1119000546
- rationalQ = 1000066
- rateTimestamp = LocalDateTime.now().minusDays(2)
- source = sourceId
- }
- val thirdExRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 2
- rationalP = 1119000229
- rationalQ = 1000077
- rateTimestamp = LocalDateTime.now().minusDays(1)
- source = sourceId
- }
- dslContext.insertInto(EX_RATE)
+ val firstExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 2
+ rationalP = 11190000264
+ rationalQ = 1000055
+ rateTimestamp = LocalDateTime.now().minusDays(3)
+ source = sourceId
+ }
+ val secondExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 2
+ rationalP = 1119000546
+ rationalQ = 1000066
+ rateTimestamp = LocalDateTime.now().minusDays(2)
+ source = sourceId
+ }
+ val thirdExRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 2
+ rationalP = 1119000229
+ rationalQ = 1000077
+ rateTimestamp = LocalDateTime.now().minusDays(1)
+ source = sourceId
+ }
+ dslContext
+ .insertInto(EX_RATE)
.set(dslContext.newRecord(EX_RATE, firstExRate))
.newRecord()
.set(dslContext.newRecord(EX_RATE, secondExRate))
@@ -173,33 +183,36 @@ class ExRateDaoImplTest : ContainerConfiguration() {
.set(dslContext.newRecord(EX_RATE, thirdExRate))
.execute()
- val requestTimestampBeforeFirstExRate = TimestampExchangeRateRequest(
- sourceCurrency = sourceCurrency,
- destinationCurrency = destinationCurrency,
- source = sourceId,
- rateTimestamp = firstExRate.rateTimestamp.minusDays(1)
- )
+ val requestTimestampBeforeFirstExRate =
+ TimestampExchangeRateRequest(
+ sourceCurrency = sourceCurrency,
+ destinationCurrency = destinationCurrency,
+ source = sourceId,
+ rateTimestamp = firstExRate.rateTimestamp.minusDays(1),
+ )
val emptyResult = exRateDao.getByCodesAndTimestamp(requestTimestampBeforeFirstExRate)
assertNull(emptyResult)
- val requestTimestampBetweenSecondAndThirdExRate = TimestampExchangeRateRequest(
- sourceCurrency = sourceCurrency,
- destinationCurrency = destinationCurrency,
- source = sourceId,
- rateTimestamp = secondExRate.rateTimestamp.plusMinutes(10)
- )
+ val requestTimestampBetweenSecondAndThirdExRate =
+ TimestampExchangeRateRequest(
+ sourceCurrency = sourceCurrency,
+ destinationCurrency = destinationCurrency,
+ source = sourceId,
+ rateTimestamp = secondExRate.rateTimestamp.plusMinutes(10),
+ )
val secondResult = exRateDao.getByCodesAndTimestamp(requestTimestampBetweenSecondAndThirdExRate)!!
assertEquals(secondExRate.rationalP, secondResult.rationalP)
assertEquals(secondExRate.rationalQ, secondResult.rationalQ)
- val requestTimestampBetweenAfterThirdExRate = TimestampExchangeRateRequest(
- sourceCurrency = sourceCurrency,
- destinationCurrency = destinationCurrency,
- source = sourceId,
- rateTimestamp = thirdExRate.rateTimestamp.plusMinutes(10)
- )
+ val requestTimestampBetweenAfterThirdExRate =
+ TimestampExchangeRateRequest(
+ sourceCurrency = sourceCurrency,
+ destinationCurrency = destinationCurrency,
+ source = sourceId,
+ rateTimestamp = thirdExRate.rateTimestamp.plusMinutes(10),
+ )
val thirdResult = exRateDao.getByCodesAndTimestamp(requestTimestampBetweenAfterThirdExRate)!!
assertEquals(thirdExRate.rationalP, thirdResult.rationalP)
diff --git a/src/test/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJobTest.kt b/src/test/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJobTest.kt
index 42e96cb..df34df5 100644
--- a/src/test/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJobTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/job/CbrExchangeGrabberJobTest.kt
@@ -17,8 +17,8 @@ import org.quartz.TriggerKey
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.boot.test.mock.mockito.MockBean
-import org.springframework.boot.test.mock.mockito.SpyBean
+import org.springframework.test.context.bean.override.mockito.MockitoBean
+import org.springframework.test.context.bean.override.mockito.MockitoSpyBean
import java.math.BigDecimal
import java.time.Instant
import java.util.concurrent.TimeUnit
@@ -27,15 +27,14 @@ import java.util.concurrent.TimeUnit
properties = [
"rates.cbr-job.jobCron=0/5 * * * * ?",
"rates.cbr-job.currencies.[0].symbolCode=RUB",
- "rates.cbr-job.currencies.[0].exponent=2"
- ]
+ "rates.cbr-job.currencies.[0].exponent=2",
+ ],
)
class CbrExchangeGrabberJobTest : ContainerConfiguration() {
-
- @SpyBean
+ @MockitoSpyBean
lateinit var exchangeDaoService: ExchangeDaoService
- @MockBean
+ @MockitoBean
lateinit var cbrExchangeRateSource: CbrExchangeRateSource
@Autowired
@@ -55,11 +54,12 @@ class CbrExchangeGrabberJobTest : ContainerConfiguration() {
whenever(cbrExchangeRateSource.getSourceId()).thenReturn("sourceId")
whenever(cbrExchangeRateSource.getExchangeRate(any())).then {
ExchangeRates(
- rates = mapOf(
- "USD" to BigDecimal.valueOf(90.593066),
- "EUR" to BigDecimal.valueOf(98.376632)
- ),
- timestamp = Instant.now().epochSecond
+ rates =
+ mapOf(
+ "USD" to BigDecimal.valueOf(90.593066),
+ "EUR" to BigDecimal.valueOf(98.376632),
+ ),
+ timestamp = Instant.now().epochSecond,
)
}
await().atMost(5, TimeUnit.SECONDS).untilAsserted {
diff --git a/src/test/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJobTest.kt b/src/test/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJobTest.kt
index fc6269e..2bba1e1 100644
--- a/src/test/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJobTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/job/FixerExchangeGrabberJobTest.kt
@@ -20,34 +20,33 @@ import org.quartz.TriggerKey
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.test.context.SpringBootTest
-import org.springframework.boot.test.mock.mockito.MockBean
-import org.springframework.boot.test.mock.mockito.SpyBean
import org.springframework.kafka.core.KafkaTemplate
import org.springframework.kafka.support.SendResult
-import org.springframework.util.concurrent.SettableListenableFuture
+import org.springframework.test.context.bean.override.mockito.MockitoBean
+import org.springframework.test.context.bean.override.mockito.MockitoSpyBean
import java.math.BigDecimal
import java.time.Instant
+import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
@SpringBootTest(
properties = [
"rates.fixer-job.jobCron=0/5 * * * * ?",
"rates.fixer-job.currencies.[0].symbolCode=USD",
- "rates.fixer-job.currencies.[0].exponent=2"
- ]
+ "rates.fixer-job.currencies.[0].exponent=2",
+ ],
)
class FixerExchangeGrabberJobTest : ContainerConfiguration() {
-
- @SpyBean
+ @MockitoSpyBean
lateinit var exchangeDaoService: ExchangeDaoService
- @SpyBean
+ @MockitoSpyBean
lateinit var exchangeEventService: ExchangeEventService
- @MockBean
+ @MockitoBean
lateinit var kafkaTemplate: KafkaTemplate
- @MockBean
+ @MockitoBean
lateinit var fixerExchangeRateSource: FixerExchangeRateSource
@Autowired
@@ -67,14 +66,15 @@ class FixerExchangeGrabberJobTest : ContainerConfiguration() {
whenever(fixerExchangeRateSource.getSourceId()).thenReturn("sourceId")
whenever(fixerExchangeRateSource.getExchangeRate(any())).then {
ExchangeRates(
- rates = mapOf(
- "AED" to BigDecimal.valueOf(3.593066),
- "AMD" to BigDecimal.valueOf(397.376632)
- ),
- timestamp = Instant.now().epochSecond
+ rates =
+ mapOf(
+ "AED" to BigDecimal.valueOf(3.593066),
+ "AMD" to BigDecimal.valueOf(397.376632),
+ ),
+ timestamp = Instant.now().epochSecond,
)
}
- val future = SettableListenableFuture>()
+ val future = CompletableFuture>()
whenever(kafkaTemplate.send(any>())).thenReturn(future)
await().atMost(30, TimeUnit.SECONDS).untilAsserted {
diff --git a/src/test/kotlin/dev/vality/rateboss/service/ExRateServiceHandlerTest.kt b/src/test/kotlin/dev/vality/rateboss/service/ExRateServiceHandlerTest.kt
index d8639db..12e46b6 100644
--- a/src/test/kotlin/dev/vality/rateboss/service/ExRateServiceHandlerTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/service/ExRateServiceHandlerTest.kt
@@ -15,15 +15,14 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.quartz.Scheduler
import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.mock.mockito.MockBean
+import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.testcontainers.junit.jupiter.Testcontainers
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
@Testcontainers
class ExRateServiceHandlerTest : ContainerConfiguration() {
-
- @MockBean
+ @MockitoBean
lateinit var scheduler: Scheduler
@Autowired
@@ -41,12 +40,13 @@ class ExRateServiceHandlerTest : ContainerConfiguration() {
fun getExchangeRateWithoutData() {
val sourceCurrency = "USD"
val destinationCurrency = "UZS"
- val request = GetCurrencyExchangeRateRequest()
- .setCurrencyData(
- CurrencyData()
- .setSourceCurrency(sourceCurrency)
- .setDestinationCurrency(destinationCurrency)
- )
+ val request =
+ GetCurrencyExchangeRateRequest()
+ .setCurrencyData(
+ CurrencyData()
+ .setSourceCurrency(sourceCurrency)
+ .setDestinationCurrency(destinationCurrency),
+ )
assertThrows { exRateServiceHandler.getExchangeRateData(request) }
}
@@ -55,25 +55,28 @@ class ExRateServiceHandlerTest : ContainerConfiguration() {
val sourceCurrency = "USD"
val destinationCurrency = "UZS"
val sourceId = "sourceId"
- val exRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 6
- rationalP = 11190000264
- rationalQ = 1000000
- rateTimestamp = LocalDateTime.now()
- source = sourceId
- }
- dslContext.insertInto(Tables.EX_RATE)
+ val exRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 6
+ rationalP = 11190000264
+ rationalQ = 1000000
+ rateTimestamp = LocalDateTime.now()
+ source = sourceId
+ }
+ dslContext
+ .insertInto(Tables.EX_RATE)
.set(dslContext.newRecord(Tables.EX_RATE, exRate))
.execute()
- val request = GetCurrencyExchangeRateRequest()
- .setCurrencyData(
- CurrencyData()
- .setSourceCurrency(sourceCurrency)
- .setDestinationCurrency(destinationCurrency)
- )
+ val request =
+ GetCurrencyExchangeRateRequest()
+ .setCurrencyData(
+ CurrencyData()
+ .setSourceCurrency(sourceCurrency)
+ .setDestinationCurrency(destinationCurrency),
+ )
val result = exRateServiceHandler.getExchangeRateData(request)
@@ -83,13 +86,13 @@ class ExRateServiceHandlerTest : ContainerConfiguration() {
@Test
fun getEmptyExRateForConvertedAmount() {
- val conversionRequest = ConversionRequest()
- .setAmount(100L)
- .setDatetime(
- LocalDateTime.now().format(DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT))
- )
- .setDestination("USD")
- .setSource("UZS")
+ val conversionRequest =
+ ConversionRequest()
+ .setAmount(100L)
+ .setDatetime(
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)),
+ ).setDestination("USD")
+ .setSource("UZS")
assertThrows(ExRateNotFound::class.java) {
exRateServiceHandler.getConvertedAmount("sourceId", conversionRequest)
@@ -101,26 +104,28 @@ class ExRateServiceHandlerTest : ContainerConfiguration() {
val sourceCurrency = "UZS"
val destinationCurrency = "USD"
val sourceId = "sourceId"
- val exRate = ExRate().apply {
- sourceCurrencySymbolicCode = sourceCurrency
- sourceCurrencyExponent = 2
- destinationCurrencySymbolicCode = destinationCurrency
- destinationCurrencyExponent = 2
- rationalP = 1398750033
- rationalQ = 125000
- rateTimestamp = LocalDateTime.now().minusDays(1)
- source = sourceId
- }
- dslContext.insertInto(Tables.EX_RATE)
+ val exRate =
+ ExRate().apply {
+ sourceCurrencySymbolicCode = sourceCurrency
+ sourceCurrencyExponent = 2
+ destinationCurrencySymbolicCode = destinationCurrency
+ destinationCurrencyExponent = 2
+ rationalP = 1398750033
+ rationalQ = 125000
+ rateTimestamp = LocalDateTime.now().minusDays(1)
+ source = sourceId
+ }
+ dslContext
+ .insertInto(Tables.EX_RATE)
.set(dslContext.newRecord(Tables.EX_RATE, exRate))
.execute()
- val conversionRequest = ConversionRequest()
- .setAmount(100L)
- .setDatetime(
- exRate.rateTimestamp.plusMinutes(10).format(DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT))
- )
- .setDestination(destinationCurrency)
- .setSource(sourceCurrency)
+ val conversionRequest =
+ ConversionRequest()
+ .setAmount(100L)
+ .setDatetime(
+ exRate.rateTimestamp.plusMinutes(10).format(DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)),
+ ).setDestination(destinationCurrency)
+ .setSource(sourceCurrency)
val result = exRateServiceHandler.getConvertedAmount(sourceId, conversionRequest)
diff --git a/src/test/kotlin/dev/vality/rateboss/service/ExchangeDaoServiceTest.kt b/src/test/kotlin/dev/vality/rateboss/service/ExchangeDaoServiceTest.kt
index edcdaba..104ce2c 100644
--- a/src/test/kotlin/dev/vality/rateboss/service/ExchangeDaoServiceTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/service/ExchangeDaoServiceTest.kt
@@ -14,13 +14,12 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.quartz.Scheduler
import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.mock.mockito.MockBean
+import org.springframework.test.context.bean.override.mockito.MockitoBean
import java.math.BigDecimal
import java.time.Instant
class ExchangeDaoServiceTest : ContainerConfiguration() {
-
- @MockBean
+ @MockitoBean
lateinit var scheduler: Scheduler
@Autowired
@@ -39,21 +38,24 @@ class ExchangeDaoServiceTest : ContainerConfiguration() {
// Given
val baseCurrencySymbolCode = "USD"
val baseCurrencyExponent = 2
- val exchangeRates = ExchangeRates(
- rates = mapOf(
- "RUB" to BigDecimal.valueOf(56.761762),
- "AED" to BigDecimal.valueOf(3.593066),
- "AMD" to BigDecimal.valueOf(397.376632)
- ),
- timestamp = Instant.now().epochSecond
- )
+ val exchangeRates =
+ ExchangeRates(
+ rates =
+ mapOf(
+ "RUB" to BigDecimal.valueOf(56.761762),
+ "AED" to BigDecimal.valueOf(3.593066),
+ "AMD" to BigDecimal.valueOf(397.376632),
+ ),
+ timestamp = Instant.now().epochSecond,
+ )
- val exchangeRatesData = ExchangeRatesData(
- destinationCurrencySymbolicCode = baseCurrencySymbolCode,
- destinationCurrencyExponent = baseCurrencyExponent.toShort(),
- exchangeRates = exchangeRates,
- sourceId = "source"
- )
+ val exchangeRatesData =
+ ExchangeRatesData(
+ destinationCurrencySymbolicCode = baseCurrencySymbolCode,
+ destinationCurrencyExponent = baseCurrencyExponent.toShort(),
+ exchangeRates = exchangeRates,
+ sourceId = "source",
+ )
// When
exchangeDaoService.saveExchangeRates(exchangeRatesData)
@@ -62,9 +64,11 @@ class ExchangeDaoServiceTest : ContainerConfiguration() {
val records = dslContext.fetch(EX_RATE)
assertEquals(exchangeRates.rates.size, records.size)
- val codes = records.stream()
- .map(ExRateRecord::getSourceCurrencySymbolicCode)
- .toList()
+ val codes =
+ records
+ .stream()
+ .map(ExRateRecord::getSourceCurrencySymbolicCode)
+ .toList()
assertThat(codes, contains("RUB", "AED", "AMD"))
}
}
diff --git a/src/test/kotlin/dev/vality/rateboss/service/ExchangeEventServiceTest.kt b/src/test/kotlin/dev/vality/rateboss/service/ExchangeEventServiceTest.kt
index 6e2554f..9749433 100644
--- a/src/test/kotlin/dev/vality/rateboss/service/ExchangeEventServiceTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/service/ExchangeEventServiceTest.kt
@@ -12,21 +12,20 @@ import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.quartz.Scheduler
import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.mock.mockito.MockBean
-import org.springframework.boot.test.mock.mockito.SpyBean
import org.springframework.kafka.core.KafkaTemplate
+import org.springframework.test.context.bean.override.mockito.MockitoBean
+import org.springframework.test.context.bean.override.mockito.MockitoSpyBean
import java.math.BigDecimal
import java.time.Instant
class ExchangeEventServiceTest : ContainerConfiguration() {
-
- @MockBean
+ @MockitoBean
lateinit var scheduler: Scheduler
@Autowired
lateinit var exchangeEventService: ExchangeEventService
- @SpyBean
+ @MockitoSpyBean
lateinit var kafkaTemplate: KafkaTemplate
@Test
@@ -34,14 +33,16 @@ class ExchangeEventServiceTest : ContainerConfiguration() {
// Given
val baseCurrencySymbolCode = "USD"
val baseCurrencyExponent = 2
- val exchangeRates = ExchangeRates(
- rates = mapOf(
- "RUB" to BigDecimal.valueOf(56.761762),
- "AED" to BigDecimal.valueOf(3.593066),
- "AMD" to BigDecimal.valueOf(397.376632)
- ),
- timestamp = Instant.now().epochSecond
- )
+ val exchangeRates =
+ ExchangeRates(
+ rates =
+ mapOf(
+ "RUB" to BigDecimal.valueOf(56.761762),
+ "AED" to BigDecimal.valueOf(3.593066),
+ "AMD" to BigDecimal.valueOf(397.376632),
+ ),
+ timestamp = Instant.now().epochSecond,
+ )
// When
exchangeEventService.sendExchangeRates(baseCurrencySymbolCode, baseCurrencyExponent.toShort(), exchangeRates)
@@ -57,13 +58,15 @@ class ExchangeEventServiceTest : ContainerConfiguration() {
val baseCurrencyExponent = 2
val rubExchangeRate = BigDecimal.valueOf(56.761762)
val btcExchangeRate = BigDecimal.valueOf(5.0203877e-05)
- val exchangeRates = ExchangeRates(
- rates = mapOf(
- "RUB" to rubExchangeRate,
- "BTC" to btcExchangeRate
- ),
- timestamp = Instant.now().epochSecond
- )
+ val exchangeRates =
+ ExchangeRates(
+ rates =
+ mapOf(
+ "RUB" to rubExchangeRate,
+ "BTC" to btcExchangeRate,
+ ),
+ timestamp = Instant.now().epochSecond,
+ )
// When
exchangeEventService.sendExchangeRates(baseCurrencySymbolCode, baseCurrencyExponent.toShort(), exchangeRates)
@@ -74,10 +77,31 @@ class ExchangeEventServiceTest : ContainerConfiguration() {
val firstRecordCurrencyEvent = argumentCaptor.allValues[0].value()
val secondRecordCurrencyEvent = argumentCaptor.allValues[1].value()
val firstRecordExchangeRate =
- BigDecimal.valueOf(firstRecordCurrencyEvent.getPayload().exchangeRate.exchange_rate.p)
- .divideAndRemainder(BigDecimal.valueOf(firstRecordCurrencyEvent.getPayload().exchangeRate.exchange_rate.q))
- val secondRecordExchangeRate = BigDecimal.valueOf(secondRecordCurrencyEvent.getPayload().exchangeRate.exchange_rate.p)
- .divide(BigDecimal.valueOf(secondRecordCurrencyEvent.getPayload().exchangeRate.exchange_rate.q))
+ BigDecimal
+ .valueOf(
+ firstRecordCurrencyEvent
+ .getPayload()
+ .exchangeRate.exchange_rate.p,
+ ).divideAndRemainder(
+ BigDecimal.valueOf(
+ firstRecordCurrencyEvent
+ .getPayload()
+ .exchangeRate.exchange_rate.q,
+ ),
+ )
+ val secondRecordExchangeRate =
+ BigDecimal
+ .valueOf(
+ secondRecordCurrencyEvent
+ .getPayload()
+ .exchangeRate.exchange_rate.p,
+ ).divide(
+ BigDecimal.valueOf(
+ secondRecordCurrencyEvent
+ .getPayload()
+ .exchangeRate.exchange_rate.q,
+ ),
+ )
assertTrue(BigDecimal("${firstRecordExchangeRate[0]}.${firstRecordExchangeRate[1]}") == rubExchangeRate)
assertTrue(secondRecordExchangeRate == btcExchangeRate)
}
diff --git a/src/test/kotlin/dev/vality/rateboss/source/CbrExchangeRateSourceTest.kt b/src/test/kotlin/dev/vality/rateboss/source/CbrExchangeRateSourceTest.kt
index 4087f28..3ff5fd8 100644
--- a/src/test/kotlin/dev/vality/rateboss/source/CbrExchangeRateSourceTest.kt
+++ b/src/test/kotlin/dev/vality/rateboss/source/CbrExchangeRateSourceTest.kt
@@ -4,7 +4,6 @@ import dev.vality.rateboss.client.cbr.CbrApiClient
import dev.vality.rateboss.client.cbr.model.CbrCurrencyData
import dev.vality.rateboss.client.cbr.model.CbrExchangeRateData
import dev.vality.rateboss.config.TestConfig
-import dev.vality.rateboss.config.properties.*
import dev.vality.rateboss.source.impl.CbrExchangeRateSource
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
@@ -12,9 +11,9 @@ import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.kotlin.any
import org.mockito.kotlin.whenever
import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.context.annotation.Import
import org.springframework.test.context.ContextConfiguration
+import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.context.junit.jupiter.SpringExtension
import org.springframework.web.client.ResourceAccessException
import java.math.BigDecimal
@@ -24,11 +23,10 @@ import java.time.LocalDate
@ContextConfiguration(classes = [CbrApiClient::class, CbrExchangeRateSource::class])
@Import(TestConfig::class)
class CbrExchangeRateSourceTest {
-
@Autowired
lateinit var exchangeRateSource: ExchangeRateSource
- @MockBean
+ @MockitoBean
lateinit var cbrApiClient: CbrApiClient
@Test
@@ -36,9 +34,10 @@ class CbrExchangeRateSourceTest {
val currencySymbolCode = "RUB"
whenever(cbrApiClient.getExchangeRates(any())).thenThrow(ResourceAccessException("Error"))
- val exception = assertThrows(ExchangeRateSourceException::class.java) {
- exchangeRateSource.getExchangeRate(currencySymbolCode)
- }
+ val exception =
+ assertThrows(ExchangeRateSourceException::class.java) {
+ exchangeRateSource.getExchangeRate(currencySymbolCode)
+ }
assertEquals("Remote client exception", exception.message)
}
@@ -50,9 +49,10 @@ class CbrExchangeRateSourceTest {
cbrExchangeRateData.currencies = emptyList()
whenever(cbrApiClient.getExchangeRates(any())).thenReturn(cbrExchangeRateData)
- val exception = assertThrows(ExchangeRateSourceException::class.java) {
- exchangeRateSource.getExchangeRate(currencySymbolCode)
- }
+ val exception =
+ assertThrows(ExchangeRateSourceException::class.java) {
+ exchangeRateSource.getExchangeRate(currencySymbolCode)
+ }
assertEquals("Unsuccessful response from CbrApi", exception.message)
}