From 07b6a164963ac67e8e777d5b4a818fdce2c54512 Mon Sep 17 00:00:00 2001 From: Bobby Sharp Date: Wed, 26 Jun 2024 12:56:45 -0400 Subject: [PATCH] refactor --- .../fqm/repository/DataRefreshRepository.java | 51 ++-- .../folio/fqm/service/DataRefreshService.java | 29 +- .../controller/DataRefreshControllerTest.java | 10 +- .../repository/DataRefreshRepositoryTest.java | 257 +++++++++--------- .../fqm/service/DataRefreshServiceTest.java | 32 ++- 5 files changed, 220 insertions(+), 159 deletions(-) diff --git a/src/main/java/org/folio/fqm/repository/DataRefreshRepository.java b/src/main/java/org/folio/fqm/repository/DataRefreshRepository.java index 853603a16..be27d04f3 100644 --- a/src/main/java/org/folio/fqm/repository/DataRefreshRepository.java +++ b/src/main/java/org/folio/fqm/repository/DataRefreshRepository.java @@ -29,26 +29,17 @@ public class DataRefreshRepository { public static final Field CURRENCY_FIELD = field("currency", String.class); public static final Field EXCHANGE_RATE_FIELD = field("exchange_rate", Double.class); + public static final String EXCHANGE_RATE_TABLE = "currency_exchange_rates"; private static final String REFRESH_MATERIALIZED_VIEW_CONCURRENTLY_SQL = "REFRESH MATERIALIZED VIEW CONCURRENTLY "; private static final String REFRESH_MATERIALIZED_VIEW_SQL = "REFRESH MATERIALIZED VIEW "; private static final String GET_EXCHANGE_RATE_PATH = "finance/exchange-rate"; private static final String GET_LOCALE_SETTINGS_PATH = "configurations/entries"; - private static final String EXCHANGE_RATE_TABLE = "currency_exchange_rates"; private static final Map GET_LOCALE_SETTINGS_PARAMS = Map.of( "query", "(module==ORG and configName==localeSettings)" ); - private static final List MATERIALIZED_VIEW_NAMES = List.of( - "drv_circulation_loan_status", - "drv_inventory_item_status", - "drv_pol_payment_status", - "drv_pol_receipt_status", - "drv_inventory_statistical_code_full", - "drv_languages" - ); - - static final List SYSTEM_SUPPORTED_CURRENCIES = List.of( + private static final List SYSTEM_SUPPORTED_CURRENCIES = List.of( "USD", "EUR", "JPY", @@ -88,24 +79,24 @@ public class DataRefreshRepository { private final SimpleHttpClient simpleHttpClient; - public DataRefreshResponse refreshData(String tenantId) { - List failedConcurrentRefreshes = refreshMaterializedViews(tenantId, MATERIALIZED_VIEW_NAMES, true); - List failedRefreshes = refreshMaterializedViews(tenantId, failedConcurrentRefreshes, false); - List successRefreshes = new ArrayList<>(MATERIALIZED_VIEW_NAMES - .stream() - .filter(matView -> !failedRefreshes.contains(matView)) - .toList()); - if (refreshExchangeRates(tenantId)) { - successRefreshes.add(EXCHANGE_RATE_TABLE); - } else { - failedRefreshes.add(EXCHANGE_RATE_TABLE); - } - return new DataRefreshResponse() - .successfulRefresh(successRefreshes) - .failedRefresh(failedRefreshes); - } - - private List refreshMaterializedViews(String tenantId, List viewsToRefresh, boolean refreshConcurrently) { +// public DataRefreshResponse refreshData(String tenantId) { +// List failedConcurrentRefreshes = refreshMaterializedViews(tenantId, MATERIALIZED_VIEW_NAMES, true); +// List failedRefreshes = refreshMaterializedViews(tenantId, failedConcurrentRefreshes, false); +// List successRefreshes = new ArrayList<>(MATERIALIZED_VIEW_NAMES +// .stream() +// .filter(matView -> !failedRefreshes.contains(matView)) +// .toList()); +// if (refreshExchangeRates(tenantId)) { +// successRefreshes.add(EXCHANGE_RATE_TABLE); +// } else { +// failedRefreshes.add(EXCHANGE_RATE_TABLE); +// } +// return new DataRefreshResponse() +// .successfulRefresh(successRefreshes) +// .failedRefresh(failedRefreshes); +// } + + public List refreshMaterializedViews(String tenantId, List viewsToRefresh, boolean refreshConcurrently) { List failedRefreshes = new ArrayList<>(); String refreshType = refreshConcurrently ? "concurrently" : "non-concurrently"; for (String matViewName : viewsToRefresh) { @@ -125,7 +116,7 @@ private List refreshMaterializedViews(String tenantId, List view return failedRefreshes; } - private boolean refreshExchangeRates(String tenantId) { + public boolean refreshExchangeRates(String tenantId) { log.info("Refreshing exchange rates"); String fullTableName = tenantId + "_mod_fqm_manager." + EXCHANGE_RATE_TABLE; String systemCurrency = getSystemCurrencyCode(); diff --git a/src/main/java/org/folio/fqm/service/DataRefreshService.java b/src/main/java/org/folio/fqm/service/DataRefreshService.java index 1ce150bc8..8ecae8470 100644 --- a/src/main/java/org/folio/fqm/service/DataRefreshService.java +++ b/src/main/java/org/folio/fqm/service/DataRefreshService.java @@ -5,12 +5,39 @@ import org.folio.fqm.repository.DataRefreshRepository; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + +import static org.folio.fqm.repository.DataRefreshRepository.EXCHANGE_RATE_TABLE; + @Service @RequiredArgsConstructor public class DataRefreshService { private final DataRefreshRepository dataRefreshRepository; + static final List MATERIALIZED_VIEW_NAMES = List.of( + "drv_circulation_loan_status", + "drv_inventory_item_status", + "drv_pol_payment_status", + "drv_pol_receipt_status", + "drv_inventory_statistical_code_full", + "drv_languages" + ); + public DataRefreshResponse refreshData(String tenantId) { - return dataRefreshRepository.refreshData(tenantId); + List failedConcurrentRefreshes = dataRefreshRepository.refreshMaterializedViews(tenantId, MATERIALIZED_VIEW_NAMES, true); + List failedRefreshes = dataRefreshRepository.refreshMaterializedViews(tenantId, failedConcurrentRefreshes, false); + List successRefreshes = new ArrayList<>(MATERIALIZED_VIEW_NAMES + .stream() + .filter(matView -> !failedRefreshes.contains(matView)) + .toList()); + if (dataRefreshRepository.refreshExchangeRates(tenantId)) { + successRefreshes.add(EXCHANGE_RATE_TABLE); + } else { + failedRefreshes.add(EXCHANGE_RATE_TABLE); + } + return new DataRefreshResponse() + .successfulRefresh(successRefreshes) + .failedRefresh(failedRefreshes); } } diff --git a/src/test/java/org/folio/fqm/controller/DataRefreshControllerTest.java b/src/test/java/org/folio/fqm/controller/DataRefreshControllerTest.java index 62bd05cfc..ec40b2fa0 100644 --- a/src/test/java/org/folio/fqm/controller/DataRefreshControllerTest.java +++ b/src/test/java/org/folio/fqm/controller/DataRefreshControllerTest.java @@ -1,5 +1,6 @@ package org.folio.fqm.controller; +import org.folio.fqm.domain.dto.DataRefreshResponse; import org.folio.fqm.resource.DataRefreshController; import org.folio.fqm.service.DataRefreshService; import org.folio.spring.FolioExecutionContext; @@ -12,6 +13,8 @@ import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import java.util.List; + import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -31,13 +34,16 @@ class DataRefreshControllerTest { @Test void refreshDataTest() throws Exception { String tenantId = "tenant_01"; + DataRefreshResponse expectedResponse = new DataRefreshResponse() + .successfulRefresh(List.of()) + .failedRefresh(List.of()); RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/entity-types/materialized-views/refresh") .header(XOkapiHeaders.TENANT, tenantId) .contentType(APPLICATION_JSON); when(executionContext.getTenantId()).thenReturn(tenantId); - doNothing().when(dataRefreshService).refreshData(tenantId); + when(dataRefreshService.refreshData(tenantId)).thenReturn(expectedResponse); mockMvc.perform(requestBuilder) - .andExpect(status().isNoContent()); + .andExpect(status().isOk()); verify(dataRefreshService, times(1)).refreshData(tenantId); } } diff --git a/src/test/java/org/folio/fqm/repository/DataRefreshRepositoryTest.java b/src/test/java/org/folio/fqm/repository/DataRefreshRepositoryTest.java index f1e203919..750ec4d8b 100644 --- a/src/test/java/org/folio/fqm/repository/DataRefreshRepositoryTest.java +++ b/src/test/java/org/folio/fqm/repository/DataRefreshRepositoryTest.java @@ -17,13 +17,14 @@ import org.mockito.stubbing.Answer; import java.util.Collection; +import java.util.List; import java.util.Map; import static org.folio.fqm.repository.DataRefreshRepository.CURRENCY_FIELD; import static org.folio.fqm.repository.DataRefreshRepository.EXCHANGE_RATE_FIELD; import static org.jooq.impl.DSL.table; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; @@ -41,144 +42,156 @@ class DataRefreshRepositoryTest { @Mock private SimpleHttpClient simpleHttpClient; + @Test + void refreshMaterializedViewsConcurrentlyTest() { + String tenantId = "tenant_01"; + List viewsToRefresh = List.of("matview1", "matview2"); + String expectedItemStatusSql = "REFRESH MATERIALIZED VIEW CONCURRENTLY tenant_01_mod_fqm_manager.matview1"; + String expectedLoanStatusSql = "REFRESH MATERIALIZED VIEW CONCURRENTLY tenant_01_mod_fqm_manager.matview2"; + when(jooqContext.execute(anyString())).thenReturn(1); + List failedRefreshes = dataRefreshRepository.refreshMaterializedViews(tenantId, viewsToRefresh, true); + verify(jooqContext, times(1)).execute(expectedItemStatusSql); + verify(jooqContext, times(1)).execute(expectedLoanStatusSql); + assertTrue(failedRefreshes.isEmpty()); + } + @Test void refreshMaterializedViewsTest() { String tenantId = "tenant_01"; - String expectedItemStatusSql = "REFRESH MATERIALIZED VIEW CONCURRENTLY tenant_01_mod_fqm_manager.drv_inventory_item_status"; - String expectedLoanStatusSql = "REFRESH MATERIALIZED VIEW CONCURRENTLY tenant_01_mod_fqm_manager.drv_circulation_loan_status"; + List viewsToRefresh = List.of("matview1", "matview2"); + String expectedItemStatusSql = "REFRESH MATERIALIZED VIEW tenant_01_mod_fqm_manager.matview1"; + String expectedLoanStatusSql = "REFRESH MATERIALIZED VIEW tenant_01_mod_fqm_manager.matview2"; when(jooqContext.execute(anyString())).thenReturn(1); - dataRefreshRepository.refreshData(tenantId); + List failedRefreshes = dataRefreshRepository.refreshMaterializedViews(tenantId, viewsToRefresh, false); verify(jooqContext, times(1)).execute(expectedItemStatusSql); verify(jooqContext, times(1)).execute(expectedLoanStatusSql); + assertTrue(failedRefreshes.isEmpty()); } @Test void shouldRefreshExchangeRates() { - fail("Fix this test"); -// String tenantId = "tenant_01"; -// String localeSettingsPath = "configurations/entries"; -// String exchangeRatePath = "finance/exchange-rate"; -// String fullTableName = "tenant_01_mod_fqm_manager.currency_exchange_rates"; -// Map localeSettingsParams = Map.of( -// "query", "(module==ORG and configName==localeSettings)" -// ); -// when(simpleHttpClient.get(localeSettingsPath, localeSettingsParams)).thenReturn(""" -// { -// "configs": [ -// { -// "id":"2a132a01-623b-4d3a-9d9a-2feb777665c2", -// "module":"ORG", -// "configName":"localeSettings", -// "enabled":true, -// "value":"{\\"locale\\":\\"en-US\\",\\"timezone\\":\\"UTC\\",\\"currency\\":\\"USD\\"}","metadata":{"createdDate":"2024-03-25T17:37:22.309+00:00","createdByUserId":"db760bf8-e05a-4a5d-a4c3-8d49dc0d4e48"} -// } -// ], -// "totalRecords": 1, -// "resultInfo": {"totalRecords":1,"facets":[],"diagnostics":[]} -// } -// """); -// when(simpleHttpClient.get(eq(exchangeRatePath), any())).thenReturn(""" -// { -// "from": "someCurrency", -// "to": "USD", -// "exchangeRate": 1.25 -// } -// """); -// -// Record2 exchangeRateMock = mock(Record2.class); -// when(jooqContext.newRecord(CURRENCY_FIELD, EXCHANGE_RATE_FIELD)) -// .thenAnswer((Answer>) invocation -> exchangeRateMock); -// when(exchangeRateMock.value1(anyString())).thenReturn(exchangeRateMock); -// when(exchangeRateMock.value2(1.25)).thenReturn(exchangeRateMock); -// -// InsertValuesStep2 insertValuesStep2Mock = mock(InsertValuesStep2.class); -// InsertOnConflictWhereIndexPredicateStep insertOnConflictWhereIndexPredicateStep = mock(InsertOnConflictWhereIndexPredicateStep.class); -// InsertOnDuplicateSetStep insertOnDuplicateSetStepMock = mock(InsertOnDuplicateSetStep.class); -// InsertOnDuplicateSetMoreStep insertOnDuplicateSetMoreStepMock = mock(InsertOnDuplicateSetMoreStep.class); -// when(jooqContext.insertInto(table(fullTableName), CURRENCY_FIELD, EXCHANGE_RATE_FIELD)).thenReturn(insertValuesStep2Mock); -// when(insertValuesStep2Mock.valuesOfRecords((Collection) any())).thenReturn(insertValuesStep2Mock); -// when(insertValuesStep2Mock.onConflict(CURRENCY_FIELD)).thenReturn(insertOnConflictWhereIndexPredicateStep); -// when(insertOnConflictWhereIndexPredicateStep.doUpdate()).thenReturn(insertOnDuplicateSetStepMock); -// when(insertOnDuplicateSetStepMock.set(EXCHANGE_RATE_FIELD, DSL.field("EXCLUDED." + EXCHANGE_RATE_FIELD.getName(), Double.class))).thenReturn(insertOnDuplicateSetMoreStepMock); -// when(insertOnDuplicateSetMoreStepMock.execute()).thenReturn(1); -// assertDoesNotThrow(() -> dataRefreshRepository.refreshExchangeRates(tenantId)); -// verify(insertOnDuplicateSetMoreStepMock, times(1)).execute(); + String tenantId = "tenant_01"; + String localeSettingsPath = "configurations/entries"; + String exchangeRatePath = "finance/exchange-rate"; + String fullTableName = "tenant_01_mod_fqm_manager.currency_exchange_rates"; + Map localeSettingsParams = Map.of( + "query", "(module==ORG and configName==localeSettings)" + ); + when(simpleHttpClient.get(localeSettingsPath, localeSettingsParams)).thenReturn(""" + { + "configs": [ + { + "id":"2a132a01-623b-4d3a-9d9a-2feb777665c2", + "module":"ORG", + "configName":"localeSettings", + "enabled":true, + "value":"{\\"locale\\":\\"en-US\\",\\"timezone\\":\\"UTC\\",\\"currency\\":\\"USD\\"}","metadata":{"createdDate":"2024-03-25T17:37:22.309+00:00","createdByUserId":"db760bf8-e05a-4a5d-a4c3-8d49dc0d4e48"} + } + ], + "totalRecords": 1, + "resultInfo": {"totalRecords":1,"facets":[],"diagnostics":[]} + } + """); + when(simpleHttpClient.get(eq(exchangeRatePath), any())).thenReturn(""" + { + "from": "someCurrency", + "to": "USD", + "exchangeRate": 1.25 + } + """); + + Record2 exchangeRateMock = mock(Record2.class); + when(jooqContext.newRecord(CURRENCY_FIELD, EXCHANGE_RATE_FIELD)) + .thenAnswer((Answer>) invocation -> exchangeRateMock); + when(exchangeRateMock.value1(anyString())).thenReturn(exchangeRateMock); + when(exchangeRateMock.value2(1.25)).thenReturn(exchangeRateMock); + + InsertValuesStep2 insertValuesStep2Mock = mock(InsertValuesStep2.class); + InsertOnConflictWhereIndexPredicateStep insertOnConflictWhereIndexPredicateStep = mock(InsertOnConflictWhereIndexPredicateStep.class); + InsertOnDuplicateSetStep insertOnDuplicateSetStepMock = mock(InsertOnDuplicateSetStep.class); + InsertOnDuplicateSetMoreStep insertOnDuplicateSetMoreStepMock = mock(InsertOnDuplicateSetMoreStep.class); + when(jooqContext.insertInto(table(fullTableName), CURRENCY_FIELD, EXCHANGE_RATE_FIELD)).thenReturn(insertValuesStep2Mock); + when(insertValuesStep2Mock.valuesOfRecords((Collection) any())).thenReturn(insertValuesStep2Mock); + when(insertValuesStep2Mock.onConflict(CURRENCY_FIELD)).thenReturn(insertOnConflictWhereIndexPredicateStep); + when(insertOnConflictWhereIndexPredicateStep.doUpdate()).thenReturn(insertOnDuplicateSetStepMock); + when(insertOnDuplicateSetStepMock.set(EXCHANGE_RATE_FIELD, DSL.field("EXCLUDED." + EXCHANGE_RATE_FIELD.getName(), Double.class))).thenReturn(insertOnDuplicateSetMoreStepMock); + when(insertOnDuplicateSetMoreStepMock.execute()).thenReturn(1); + assertDoesNotThrow(() -> dataRefreshRepository.refreshExchangeRates(tenantId)); + verify(insertOnDuplicateSetMoreStepMock, times(1)).execute(); } @Test void shouldDoNothingIfSystemCurrencyIsNotSupported() { - fail("Fix this test"); -// String tenantId = "tenant_01"; -// String localeSettingsPath = "configurations/entries"; -// String fullTableName = "tenant_01_mod_fqm_manager.currency_exchange_rates"; -// Map localeSettingsParams = Map.of( -// "query", "(module==ORG and configName==localeSettings)" -// ); -// when(simpleHttpClient.get(localeSettingsPath, localeSettingsParams)).thenReturn(""" -// { -// "configs": [ -// { -// "id":"2a132a01-623b-4d3a-9d9a-2feb777665c2", -// "module":"ORG", -// "configName":"localeSettings", -// "enabled":true, -// "value":"{\\"locale\\":\\"en-US\\",\\"timezone\\":\\"UTC\\",\\"currency\\":\\"ZWD\\"}","metadata":{"createdDate":"2024-03-25T17:37:22.309+00:00","createdByUserId":"db760bf8-e05a-4a5d-a4c3-8d49dc0d4e48"} -// } -// ], -// "totalRecords": 1, -// "resultInfo": {"totalRecords":1,"facets":[],"diagnostics":[]} -// } -// """); -// assertDoesNotThrow(() -> dataRefreshRepository.refreshExchangeRates(tenantId)); -// verify(jooqContext, times(0)).insertInto(table(fullTableName)); + String tenantId = "tenant_01"; + String localeSettingsPath = "configurations/entries"; + String fullTableName = "tenant_01_mod_fqm_manager.currency_exchange_rates"; + Map localeSettingsParams = Map.of( + "query", "(module==ORG and configName==localeSettings)" + ); + when(simpleHttpClient.get(localeSettingsPath, localeSettingsParams)).thenReturn(""" + { + "configs": [ + { + "id":"2a132a01-623b-4d3a-9d9a-2feb777665c2", + "module":"ORG", + "configName":"localeSettings", + "enabled":true, + "value":"{\\"locale\\":\\"en-US\\",\\"timezone\\":\\"UTC\\",\\"currency\\":\\"ZWD\\"}","metadata":{"createdDate":"2024-03-25T17:37:22.309+00:00","createdByUserId":"db760bf8-e05a-4a5d-a4c3-8d49dc0d4e48"} + } + ], + "totalRecords": 1, + "resultInfo": {"totalRecords":1,"facets":[],"diagnostics":[]} + } + """); + assertDoesNotThrow(() -> dataRefreshRepository.refreshExchangeRates(tenantId)); + verify(jooqContext, times(0)).insertInto(table(fullTableName)); } @Test void shouldUseUSDAsDefaultCurrencyIfSystemCurrencyNotDefined() { - fail("Fix this test"); -// String tenantId = "tenant_01"; -// String localeSettingsPath = "configurations/entries"; -// String exchangeRatePath = "finance/exchange-rate"; -// String fullTableName = "tenant_01_mod_fqm_manager.currency_exchange_rates"; -// Map exchangeRateParams = Map.of( -// "from", "USD", -// "to", "USD" -// ); -// Map localeSettingsParams = Map.of( -// "query", "(module==ORG and configName==localeSettings)" -// ); -// when(simpleHttpClient.get(localeSettingsPath, localeSettingsParams)).thenReturn(""" -// { -// "configs": [], -// "totalRecords": 0, -// "resultInfo": {"totalRecords":0,"facets":[],"diagnostics":[]} -// } -// """); -// when(simpleHttpClient.get(exchangeRatePath, exchangeRateParams)).thenReturn(""" -// { -// "from": "ZAR", -// "to": "USD", -// "exchangeRate": 1.1234567890123456789 -// } -// """); -// -// Record2 exchangeRateMock = mock(Record2.class); -// when(jooqContext.newRecord(CURRENCY_FIELD, EXCHANGE_RATE_FIELD)) -// .thenAnswer((Answer>) invocation -> exchangeRateMock); -// when(exchangeRateMock.value1(anyString())).thenReturn(exchangeRateMock); -// when(exchangeRateMock.value2(1.1234567890123456789)).thenReturn(exchangeRateMock); -// -// InsertValuesStep2 insertValuesStep2Mock = mock(InsertValuesStep2.class); -// InsertOnConflictWhereIndexPredicateStep insertOnConflictWhereIndexPredicateStep = mock(InsertOnConflictWhereIndexPredicateStep.class); -// InsertOnDuplicateSetStep insertOnDuplicateSetStepMock = mock(InsertOnDuplicateSetStep.class); -// InsertOnDuplicateSetMoreStep insertOnDuplicateSetMoreStepMock = mock(InsertOnDuplicateSetMoreStep.class); -// when(jooqContext.insertInto(table(fullTableName), CURRENCY_FIELD, EXCHANGE_RATE_FIELD)).thenReturn(insertValuesStep2Mock); -// when(insertValuesStep2Mock.valuesOfRecords((Collection) any())).thenReturn(insertValuesStep2Mock); -// when(insertValuesStep2Mock.onConflict(CURRENCY_FIELD)).thenReturn(insertOnConflictWhereIndexPredicateStep); -// when(insertOnConflictWhereIndexPredicateStep.doUpdate()).thenReturn(insertOnDuplicateSetStepMock); -// when(insertOnDuplicateSetStepMock.set(EXCHANGE_RATE_FIELD, DSL.field("EXCLUDED." + EXCHANGE_RATE_FIELD.getName(), Double.class))).thenReturn(insertOnDuplicateSetMoreStepMock); -// when(insertOnDuplicateSetMoreStepMock.execute()).thenReturn(1); -// assertDoesNotThrow(() -> dataRefreshRepository.refreshExchangeRates(tenantId)); -// verify(insertOnDuplicateSetMoreStepMock, times(1)).execute(); + String tenantId = "tenant_01"; + String localeSettingsPath = "configurations/entries"; + String exchangeRatePath = "finance/exchange-rate"; + String fullTableName = "tenant_01_mod_fqm_manager.currency_exchange_rates"; + Map exchangeRateParams = Map.of( + "from", "USD", + "to", "USD" + ); + Map localeSettingsParams = Map.of( + "query", "(module==ORG and configName==localeSettings)" + ); + when(simpleHttpClient.get(localeSettingsPath, localeSettingsParams)).thenReturn(""" + { + "configs": [], + "totalRecords": 0, + "resultInfo": {"totalRecords":0,"facets":[],"diagnostics":[]} + } + """); + when(simpleHttpClient.get(exchangeRatePath, exchangeRateParams)).thenReturn(""" + { + "from": "ZAR", + "to": "USD", + "exchangeRate": 1.1234567890123456789 + } + """); + + Record2 exchangeRateMock = mock(Record2.class); + when(jooqContext.newRecord(CURRENCY_FIELD, EXCHANGE_RATE_FIELD)) + .thenAnswer((Answer>) invocation -> exchangeRateMock); + when(exchangeRateMock.value1(anyString())).thenReturn(exchangeRateMock); + when(exchangeRateMock.value2(1.1234567890123456789)).thenReturn(exchangeRateMock); + + InsertValuesStep2 insertValuesStep2Mock = mock(InsertValuesStep2.class); + InsertOnConflictWhereIndexPredicateStep insertOnConflictWhereIndexPredicateStep = mock(InsertOnConflictWhereIndexPredicateStep.class); + InsertOnDuplicateSetStep insertOnDuplicateSetStepMock = mock(InsertOnDuplicateSetStep.class); + InsertOnDuplicateSetMoreStep insertOnDuplicateSetMoreStepMock = mock(InsertOnDuplicateSetMoreStep.class); + when(jooqContext.insertInto(table(fullTableName), CURRENCY_FIELD, EXCHANGE_RATE_FIELD)).thenReturn(insertValuesStep2Mock); + when(insertValuesStep2Mock.valuesOfRecords((Collection) any())).thenReturn(insertValuesStep2Mock); + when(insertValuesStep2Mock.onConflict(CURRENCY_FIELD)).thenReturn(insertOnConflictWhereIndexPredicateStep); + when(insertOnConflictWhereIndexPredicateStep.doUpdate()).thenReturn(insertOnDuplicateSetStepMock); + when(insertOnDuplicateSetStepMock.set(EXCHANGE_RATE_FIELD, DSL.field("EXCLUDED." + EXCHANGE_RATE_FIELD.getName(), Double.class))).thenReturn(insertOnDuplicateSetMoreStepMock); + when(insertOnDuplicateSetMoreStepMock.execute()).thenReturn(1); + assertDoesNotThrow(() -> dataRefreshRepository.refreshExchangeRates(tenantId)); + verify(insertOnDuplicateSetMoreStepMock, times(1)).execute(); } } diff --git a/src/test/java/org/folio/fqm/service/DataRefreshServiceTest.java b/src/test/java/org/folio/fqm/service/DataRefreshServiceTest.java index 4ee68816d..afab251c8 100644 --- a/src/test/java/org/folio/fqm/service/DataRefreshServiceTest.java +++ b/src/test/java/org/folio/fqm/service/DataRefreshServiceTest.java @@ -8,9 +8,14 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.ArrayList; import java.util.List; +import static org.folio.fqm.repository.DataRefreshRepository.EXCHANGE_RATE_TABLE; +import static org.folio.fqm.service.DataRefreshService.MATERIALIZED_VIEW_NAMES; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -23,11 +28,30 @@ class DataRefreshServiceTest { @Test void refreshDataTest() { String tenantId = "tenant_01"; + List expectedSuccessRefreshViews = new ArrayList<>(MATERIALIZED_VIEW_NAMES); + expectedSuccessRefreshViews.add(EXCHANGE_RATE_TABLE); DataRefreshResponse expectedDataRefreshResponse = new DataRefreshResponse() - .successfulRefresh(List.of("matview1")) - .failedRefresh(List.of("matview2")); - when(dataRefreshRepository.refreshData(tenantId)).thenReturn(expectedDataRefreshResponse); - DataRefreshResponse actualDataRefreshResponse = dataRefreshRepository.refreshData(tenantId); + .successfulRefresh(expectedSuccessRefreshViews) + .failedRefresh(List.of()); + when(dataRefreshRepository.refreshMaterializedViews(tenantId, MATERIALIZED_VIEW_NAMES, true)).thenReturn(List.of()); + when(dataRefreshRepository.refreshExchangeRates(tenantId)).thenReturn(true); + DataRefreshResponse actualDataRefreshResponse = dataRefreshService.refreshData(tenantId); + assertEquals(expectedDataRefreshResponse, actualDataRefreshResponse); + } + + @Test + void shouldRetryRefreshIfConcurrentRefreshFails() { + String tenantId = "tenant_01"; + List expectedSuccessRefreshViews = new ArrayList<>(MATERIALIZED_VIEW_NAMES); + expectedSuccessRefreshViews.add(EXCHANGE_RATE_TABLE); + DataRefreshResponse expectedDataRefreshResponse = new DataRefreshResponse() + .successfulRefresh(expectedSuccessRefreshViews) + .failedRefresh(List.of()); + when(dataRefreshRepository.refreshMaterializedViews(tenantId, MATERIALIZED_VIEW_NAMES, true)).thenReturn(List.of("drv_languages")); + when(dataRefreshRepository.refreshMaterializedViews(tenantId, List.of("drv_languages"), false)).thenReturn(List.of()); + when(dataRefreshRepository.refreshExchangeRates(tenantId)).thenReturn(true); + DataRefreshResponse actualDataRefreshResponse = dataRefreshService.refreshData(tenantId); + verify(dataRefreshRepository, times(1)).refreshMaterializedViews(tenantId, List.of("drv_languages"), false); assertEquals(expectedDataRefreshResponse, actualDataRefreshResponse); } }