cache = new ConcurrentHashMap<>(1);
-
- public double getSellRate(String currency) {
- return getCurrency(currency).sell();
- }
-
- public double getBuyRate(String currency) {
- return getCurrency(currency).buy();
- }
-
- private synchronized RatesCache getCurrency(String currency) {
- var today = getFetchDate();
- var cacheObject = cache.get(currency);
- if (cacheObject == null || cacheObject.date().isBefore(today)) {
- var fresh = fetchData(currency, dtf.format(today));
- var rate = fresh.getRates().get(0);
- cacheObject = new RatesCache(
- LocalDate.parse(rate.getEffectiveDate(), dtf),
- rate.getBid(),
- rate.getAsk()
- );
- cache.put(fresh.getCode(), cacheObject);
- }
- return cacheObject;
- }
-
- /**
- * Calculates date for data fetch.
- *
- * Usually this would be today, but as rates are set only Mon-Fri, during weekends it is needed to fetch last friday rates.
- *
- * @return date for data fetch
- */
- @VisibleForTesting
- LocalDate getFetchDate() {
- var today = LocalDate.now(clock);
- return isWeekend(today) ? today.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY)) : today;
- }
-
- @VisibleForTesting
- Rates fetchData(String code, String date) {
- return restClient.get().uri(URI_PATTERN, code.toLowerCase(), date)
- .retrieve()
- .onStatus(HttpStatusCode::is4xxClientError, ((request, response) -> {
- throw new NoDataException(code, date);
- }))
- .body(Rates.class);
- }
-
- private static boolean isWeekend(LocalDate today) {
- return today.getDayOfWeek() == DayOfWeek.SATURDAY
- || today.getDayOfWeek() == DayOfWeek.SUNDAY;
- }
-
- private record RatesCache(LocalDate date, double buy, double sell) {
-
- }
-
-}
diff --git a/src/main/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidator.java b/src/main/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidator.java
index 0895d92..43d4f1f 100644
--- a/src/main/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidator.java
+++ b/src/main/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidator.java
@@ -4,21 +4,12 @@ import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
-public class ValidExchangeRequestValidator implements
- ConstraintValidator {
+public class ValidExchangeRequestValidator implements ConstraintValidator {
@Override
- public boolean isValid(CurrencyExchangeRequest request,
+ public boolean isValid(CurrencyExchangeRequest currencyExchangeRequest,
ConstraintValidatorContext constraintValidatorContext) {
- if (request == null) {
- return false;
- }
-
- return !request.from().equals(request.to())
- && !((request.toBuy() == null && request.toSell() == null)
- || (request.toBuy() != null && request.toSell() != null))
- && ((request.toBuy() != null && request.toBuy() >= 0)
- || (request.toSell() != null && request.toSell() >= 0));
+ return false;
}
}
diff --git a/src/main/resources/schema/rates.json b/src/main/resources/schema/rates.json
deleted file mode 100644
index 2ed42d0..0000000
--- a/src/main/resources/schema/rates.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "$id": "https://api.nbp.pl/c/rates.json",
- "$schema": "http://json-schema.org/draft/2020-12/schema",
- "type": "object",
- "def": {
- "rate": {
- "type": "object",
- "properties": {
- "no": {
- "type": "string"
- },
- "effectiveDate": {
- "type": "string"
- },
- "bid": {
- "type": "number"
- },
- "ask": {
- "type": "number"
- }
- },
- "required": [
- "no",
- "effectiveDate",
- "bid",
- "ask"
- ]
- }
- },
- "properties": {
- "table": {
- "type": "string"
- },
- "currency": {
- "type": "string"
- },
- "code": {
- "type": "string"
- },
- "rates": {
- "type": "array",
- "items": {
- "$ref": "#/def/rate"
- }
- }
- },
- "required": [
- "table",
- "currency",
- "code",
- "rates"
- ]
-}
diff --git a/src/test/java/eu/ztsh/wymiana/EntityCreator.java b/src/test/java/eu/ztsh/wymiana/EntityCreator.java
index df78b20..4f7fcd7 100644
--- a/src/test/java/eu/ztsh/wymiana/EntityCreator.java
+++ b/src/test/java/eu/ztsh/wymiana/EntityCreator.java
@@ -2,9 +2,6 @@ package eu.ztsh.wymiana;
import eu.ztsh.wymiana.data.entity.CurrencyEntity;
import eu.ztsh.wymiana.data.entity.UserEntity;
-import eu.ztsh.wymiana.model.Rate;
-import eu.ztsh.wymiana.model.Rates;
-import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
import eu.ztsh.wymiana.web.model.UserCreateRequest;
import java.util.ArrayList;
@@ -19,12 +16,6 @@ public class EntityCreator {
public static String NAME = "Janina";
public static String SURNAME = "Kowalska";
public static double PLN = 20.10;
- public static double USD_SELL = 5.18;
- public static double USD_BUY = 5.08;
- public static String PLN_SYMBOL = "PLN";
- public static String USD_SYMBOL = "USD";
- public static double BUY_RATE = 3.8804;
- public static double SELL_RATE = 3.9572;
}
@@ -39,24 +30,6 @@ public class EntityCreator {
.pln(Constants.PLN);
}
- public static CurrencyExchangeRequest.CurrencyExchangeRequestBuilder exchangeRequest() {
- return CurrencyExchangeRequest.builder().pesel(Constants.PESEL);
- }
-
- public static Rates rates(String date) {
- var rates = new Rates();
- rates.setTable("C");
- rates.setCurrency("dolar amerykaĆski");
- rates.setCode("USD");
- var rate = new Rate();
- rate.setNo("096/C/NBP/2024");
- rate.setEffectiveDate(date);
- rate.setBid(Constants.BUY_RATE);
- rate.setAsk(Constants.SELL_RATE);
- rates.setRates(List.of(rate));
- return rates;
- }
-
public static class UserEntityBuilder {
String name;
diff --git a/src/test/java/eu/ztsh/wymiana/WireMockExtension.java b/src/test/java/eu/ztsh/wymiana/WireMockExtension.java
deleted file mode 100644
index 99ebc73..0000000
--- a/src/test/java/eu/ztsh/wymiana/WireMockExtension.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package eu.ztsh.wymiana;
-
-import com.github.tomakehurst.wiremock.WireMockServer;
-import com.github.tomakehurst.wiremock.client.WireMock;
-import org.junit.jupiter.api.extension.AfterEachCallback;
-import org.junit.jupiter.api.extension.BeforeAllCallback;
-import org.junit.jupiter.api.extension.ExtensionContext;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.*;
-
-public class WireMockExtension implements BeforeAllCallback, AfterEachCallback, ExtensionContext.Store.CloseableResource {
-
- public static final String baseUrl = "http://localhost:38080";
-
- public static void response(String endpoint, int status, String body) {
- configureFor(38080);
- stubFor(get(urlEqualTo(endpoint))
- .willReturn(WireMock.status(status)
- .withHeader("Content-Type", "application/json")
- .withBody(body)));
- }
-
- public static void verifyGet(int count, String url) {
- verify(exactly(count), getRequestedFor(urlEqualTo(url)));
- }
-
- private static final WireMockServer wireMockServer = new WireMockServer(38080);
- private boolean started;
-
- @Override
- public void beforeAll(ExtensionContext extensionContext) throws Exception {
- if (!started) {
- wireMockServer.start();
- started = true;
- }
- }
- @Override
- public void afterEach(ExtensionContext extensionContext) throws Exception {
- wireMockServer.listAllStubMappings().getMappings().forEach(wireMockServer::removeStub);
- wireMockServer.findAllUnmatchedRequests().forEach(System.out::println);
- wireMockServer.resetRequests();
- }
-
- @Override
- public void close() throws Throwable {
- wireMockServer.stop();
- }
-
-
-}
diff --git a/src/test/java/eu/ztsh/wymiana/service/NbpServiceTest.java b/src/test/java/eu/ztsh/wymiana/service/NbpServiceTest.java
deleted file mode 100644
index 7424fbe..0000000
--- a/src/test/java/eu/ztsh/wymiana/service/NbpServiceTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package eu.ztsh.wymiana.service;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import eu.ztsh.wymiana.EntityCreator;
-import eu.ztsh.wymiana.WireMockExtension;
-import eu.ztsh.wymiana.exception.NoDataException;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
-import org.mockito.Mockito;
-import org.springframework.web.client.RestClient;
-
-import java.time.Clock;
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.Month;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.TemporalAdjusters;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-@ExtendWith(WireMockExtension.class)
-class NbpServiceTest {
-
- private static final ZoneId zone = ZoneId.of("Europe/Warsaw");
- private static final LocalDate today = LocalDate.of(2024, Month.MAY, 12); // Sunday
- private static Clock clock;
- private final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
- private final RestClient restClient = RestClient.builder().baseUrl(WireMockExtension.baseUrl).build();
- private NbpService nbpService;
-
- @BeforeAll
- static void prepare() {
- clock = Mockito.mock(Clock.class);
- Mockito.when(clock.getZone()).thenReturn(zone);
- }
-
- @BeforeEach
- void prepareTest() {
- nbpService = new NbpService(clock, restClient);
- }
-
- @DisplayName("Check if fetch date is calculated properly: weekdays")
- @ParameterizedTest
- @EnumSource(value = DayOfWeek.class, names = {"SATURDAY", "SUNDAY"}, mode = EnumSource.Mode.EXCLUDE)
- void getFetchDateOnWorkingDayTest(DayOfWeek dayOfWeek) {
- updateClock(dayOfWeek);
- assertThat(nbpService.getFetchDate()).isEqualTo(
- switch (dayOfWeek) {
- case MONDAY -> LocalDate.of(2024, Month.MAY, 6);
- case TUESDAY -> LocalDate.of(2024, Month.MAY, 7);
- case WEDNESDAY -> LocalDate.of(2024, Month.MAY, 8);
- case THURSDAY -> LocalDate.of(2024, Month.MAY, 9);
- case FRIDAY -> LocalDate.of(2024, Month.MAY, 10);
- default -> null;
- }
- );
- }
-
- @DisplayName("Check if fetch date is calculated properly: weekends")
- @ParameterizedTest
- @EnumSource(value = DayOfWeek.class, names = {"SATURDAY", "SUNDAY"})
- void getFetchDateOnWeekendTest(DayOfWeek dayOfWeek) {
- updateClock(dayOfWeek);
- assertThat(nbpService.getFetchDate()).isEqualTo(LocalDate.of(2024, Month.MAY, 10));
- }
-
- @DisplayName("Fetch rates straight from server")
- @Test
- void getWithoutCacheTest() throws JsonProcessingException {
- var date = dtf.format(updateClock(DayOfWeek.FRIDAY));
- var url = "/api/exchangerates/rates/c/usd/%s/".formatted(date);
- WireMockExtension.response(url, 200, new ObjectMapper().writeValueAsString(EntityCreator.rates(date)));
- try {
- assertThat(nbpService.getSellRate(EntityCreator.Constants.USD_SYMBOL)).isEqualTo(EntityCreator.Constants.SELL_RATE);
- } finally {
- WireMockExtension.verifyGet(1, url);
- }
- }
-
- @DisplayName("Fetch rates from cache")
- @Test
- void getWithCacheTest() throws JsonProcessingException {
- var date = dtf.format(updateClock(DayOfWeek.FRIDAY));
- var url = "/api/exchangerates/rates/c/usd/%s/".formatted(date);
- WireMockExtension.response(url, 200, new ObjectMapper().writeValueAsString(EntityCreator.rates(date)));
- // save to cache
- assertThat(nbpService.getSellRate(EntityCreator.Constants.USD_SYMBOL)).isEqualTo(EntityCreator.Constants.SELL_RATE);
- // get from cache
- assertThat(nbpService.getBuyRate(EntityCreator.Constants.USD_SYMBOL)).isEqualTo(EntityCreator.Constants.BUY_RATE);
- WireMockExtension.verifyGet(1, url);
- }
-
- @DisplayName("Support 404: invalid currency or no data")
- @Test
- void getInvalidCurrencyTest() {
- var date = dtf.format(updateClock(DayOfWeek.FRIDAY));
- var url = "/api/exchangerates/rates/c/usb/%s/".formatted(date);
- WireMockExtension.response(url, 404, "404 NotFound - Not Found - Brak danych");
- assertThatThrownBy(() -> nbpService.getSellRate("usb")).isInstanceOf(NoDataException.class);
- WireMockExtension.verifyGet(1, url);
- }
-
- private LocalDate updateClock(DayOfWeek dayOfWeek) {
- var date = today.with(TemporalAdjusters.previousOrSame(dayOfWeek));
- Mockito.when(clock.instant()).thenReturn(date.atStartOfDay(zone).toInstant());
- return LocalDate.from(date);
- }
-
-}
diff --git a/src/test/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidatorTest.java b/src/test/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidatorTest.java
index 85161e6..e990658 100644
--- a/src/test/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidatorTest.java
+++ b/src/test/java/eu/ztsh/wymiana/validation/ValidExchangeRequestValidatorTest.java
@@ -1,16 +1,8 @@
package eu.ztsh.wymiana.validation;
-import eu.ztsh.wymiana.EntityCreator;
import eu.ztsh.wymiana.web.model.CurrencyExchangeRequest;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import java.util.stream.Stream;
-
-import static eu.ztsh.wymiana.EntityCreator.Constants.*;
class ValidExchangeRequestValidatorTest extends ValidatorTest {
@@ -21,108 +13,42 @@ class ValidExchangeRequestValidatorTest extends ValidatorTest invalidPeselTest() {
- return Stream.of("INVALID", PESEL.replace('6', '7'));
}
}