diff --git a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java index c1f71605e..d3667f95b 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java +++ b/src/main/java/org/breedinginsight/brapi/v2/dao/BrAPIGermplasmDAO.java @@ -219,8 +219,12 @@ private Map processGermplasmForDisplay(List importBrAPIGermplasm(List brAPIGermplasmList, UUID programId, ImportUpload upload) throws ApiException { GermplasmApi api = new GermplasmApi(programDAO.getCoreClient(programId)); + var program = programDAO.fetchOneById(programId); try { - Callable> postFunction = () -> brAPIDAOUtil.post(brAPIGermplasmList, upload, api::germplasmPost, importDAO::update); + Callable> postFunction = () -> { + List postResponse = brAPIDAOUtil.post(brAPIGermplasmList, upload, api::germplasmPost, importDAO::update); + return processGermplasmForDisplay(postResponse, program.getKey()); + }; return programGermplasmCache.post(programId, postFunction); } catch (ApiException e) { throw e; diff --git a/src/main/java/org/breedinginsight/brapi/v2/dao/ProgramCache.java b/src/main/java/org/breedinginsight/brapi/v2/dao/ProgramCache.java index 30361e983..027fd5280 100644 --- a/src/main/java/org/breedinginsight/brapi/v2/dao/ProgramCache.java +++ b/src/main/java/org/breedinginsight/brapi/v2/dao/ProgramCache.java @@ -129,9 +129,17 @@ private void updateCache(UUID programId) { } } - public List post(UUID programId, Callable> postMethod) throws Exception { - List response = postMethod.call(); + public List post(UUID programId, Callable> postMethod) throws Exception { + Map response = postMethod.call(); + + Map map = cache.getIfPresent(programId); + if(map != null) { + map.putAll(response); + } else { + cache.put(programId, response); + } + updateCache(programId); - return response; + return new ArrayList<>(response.values()); } } diff --git a/src/test/java/org/breedinginsight/brapi/v2/ProgramCacheUnitTest.java b/src/test/java/org/breedinginsight/brapi/v2/ProgramCacheUnitTest.java index cb72cca48..1fb896ca6 100644 --- a/src/test/java/org/breedinginsight/brapi/v2/ProgramCacheUnitTest.java +++ b/src/test/java/org/breedinginsight/brapi/v2/ProgramCacheUnitTest.java @@ -20,6 +20,7 @@ import javax.inject.Inject; import java.util.*; import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.*; @@ -36,7 +37,7 @@ public class ProgramCacheUnitTest { // POSTing refresh tracking separate for each program // Cache refresh failure invalidates cache - Integer fetchCount = 0; + AtomicInteger fetchCount = new AtomicInteger(0); Integer waitTime = 1000; Map> mockBrAPI = new HashMap<>(); @@ -53,26 +54,28 @@ void setup() {} void setupNextTest() { // There is some thread sleeping used in this testing, wait for all processes to clean out between tests Thread.sleep(5000); - fetchCount = 0; + fetchCount.set(0); mockBrAPI = new HashMap<>(); } @SneakyThrows public Map mockFetch(UUID programId, Integer sleepTime) { - fetchCount += 1; + fetchCount.incrementAndGet(); Thread.sleep(sleepTime); return mockBrAPI.containsKey(programId) ? new HashMap<>(mockBrAPI.get(programId).stream().collect(Collectors.toMap(germplasm -> UUID.randomUUID().toString(), germplasm -> germplasm))) : new HashMap<>(); } @SneakyThrows - public List mockPost(UUID programId, List germplasm) { + public Map mockPost(UUID programId, List germplasm) { if (!mockBrAPI.containsKey(programId)) { mockBrAPI.put(programId, germplasm); } else { List allGermplasm = mockBrAPI.get(programId); allGermplasm.addAll(germplasm); } - return germplasm; + Map germMap = new HashMap<>(); + germplasm.forEach(brAPIGermplasm -> germMap.put(brAPIGermplasm.getGermplasmDbId(), brAPIGermplasm)); + return germMap; } @Test @@ -85,11 +88,11 @@ public void populatedRefreshQueueSkipsRefresh() { int currPost = 0; while (currPost < numPost) { List newList = new ArrayList<>(); - newList.add(new BrAPIGermplasm()); + newList.add(new BrAPIGermplasm().germplasmDbId(UUID.randomUUID().toString())); cache.post(programId, () -> mockPost(programId, new ArrayList<>(newList))); currPost += 1; } - assertTrue(fetchCount < numPost, "A fetch call was made for every post. It shouldn't."); + assertTrue(fetchCount.get() < numPost, "A fetch call was made for every post. It shouldn't."); assertEquals(1, mockBrAPI.size(), "More than one program existed in mocked brapi db."); assertEquals(numPost, mockBrAPI.get(programId).size(), "Wrong number of germplasm in db"); Map cachedGermplasm = cache.get(programId); @@ -106,13 +109,12 @@ public void programRefreshesSeparated() { while (currPost < numPost) { UUID id = UUID.randomUUID(); List newList = new ArrayList<>(); - newList.add(new BrAPIGermplasm()); + newList.add(new BrAPIGermplasm().germplasmDbId(UUID.randomUUID().toString())); cache.post(id, () -> mockPost(id, new ArrayList<>(newList))); - // This doesn't have to do with our code, our mock function is just tripping over itself trying to update the number of fetches - Thread.sleep(waitTime/5); currPost += 1; } - assertEquals(numPost, fetchCount, "A fetch call should have been made for every post"); + Thread.sleep(waitTime); + assertEquals(numPost, fetchCount.get(), "A fetch call should have been made for every post"); assertEquals(numPost, mockBrAPI.size(), "Less programs existed than existed in mock brapi db."); for (UUID key: mockBrAPI.keySet()) { assertEquals(1, mockBrAPI.get(key).size(), "Wrong number of germplasm in db"); @@ -128,19 +130,19 @@ public void initialGetMethodWaitsForLoad() { ProgramCache cache = new ProgramCache<>((UUID id) -> mockFetch(id, waitTime), List.of(programId)); cache.get(programId); // Our fetch method should have only been called once for the initial loading - assertEquals(1, fetchCount, "Fetch method was called on get"); + assertEquals(1, fetchCount.get(), "Fetch method was called on get"); } @Test @SneakyThrows - public void getMethodDoesNotWaitForRefresh() { + public void postTriggersRefresh() { // Test that the get method does not wait for a refresh when there is data present UUID programId = UUID.randomUUID(); List newList = new ArrayList<>(); - newList.add(new BrAPIGermplasm()); + newList.add(new BrAPIGermplasm().germplasmDbId(UUID.randomUUID().toString())); mockBrAPI.put(programId, new ArrayList<>(newList)); ProgramCache cache = new ProgramCache<>((UUID id) -> mockFetch(id, waitTime*2), List.of(programId)); - Callable> postFunction = () -> mockPost(programId, new ArrayList<>(newList)); + Callable> postFunction = () -> mockPost(programId, new ArrayList<>(newList)); // Get waits for initial fetch Map cachedGermplasm = cache.get(programId); @@ -149,7 +151,7 @@ public void getMethodDoesNotWaitForRefresh() { // Now post another object and call get immediately to see that it returns the old data cache.post(programId, postFunction); cachedGermplasm = cache.get(programId); - assertEquals(1, cachedGermplasm.size(), "Get method seemed to have waited for refresh method"); + assertEquals(2, cachedGermplasm.size(), "Get post method didn't insert the new data"); // Now wait for the fetch after the post to finish Thread.sleep(waitTime*3); @@ -167,7 +169,7 @@ public void refreshErrorInvalidatesCache() { // Set starter data UUID programId = UUID.randomUUID(); List newList = new ArrayList<>(); - newList.add(new BrAPIGermplasm()); + newList.add(new BrAPIGermplasm().germplasmDbId(UUID.randomUUID().toString())); mockBrAPI.put(programId, new ArrayList<>(newList)); // Mock our method