From 81b01e25b19c82d3c010af001bf4a9bf6e30ce26 Mon Sep 17 00:00:00 2001 From: Elliot Otchet Date: Wed, 5 Feb 2025 16:05:33 -0500 Subject: [PATCH] Refactors to introduce DraftServiceDAO and DraftFileStorageServiceDAO so that two level mocks aren't needed for GCSService --- .../consent/http/ConsentApplication.java | 1 + .../consent/http/ConsentModule.java | 12 +- .../consent/http/service/DraftService.java | 170 +++--------- .../consent/http/service/UserService.java | 9 +- .../DraftFileStorageServiceDAO.java} | 10 +- .../http/service/dao/DraftServiceDAO.java | 156 +++++++++++ .../http/resources/DraftResourceTest.java | 7 +- .../http/service/DraftServiceTest.java | 239 +++-------------- .../consent/http/service/UserServiceTest.java | 5 +- .../DraftFileStorageServiceDAOTest.java} | 35 +-- .../http/service/dao/DraftServiceDAOTest.java | 242 ++++++++++++++++++ 11 files changed, 493 insertions(+), 393 deletions(-) rename src/main/java/org/broadinstitute/consent/http/service/{DraftFileStorageService.java => dao/DraftFileStorageServiceDAO.java} (92%) create mode 100644 src/main/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAO.java rename src/test/java/org/broadinstitute/consent/http/service/{DraftFileStorageServiceTest.java => dao/DraftFileStorageServiceDAOTest.java} (73%) create mode 100644 src/test/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAOTest.java diff --git a/src/main/java/org/broadinstitute/consent/http/ConsentApplication.java b/src/main/java/org/broadinstitute/consent/http/ConsentApplication.java index e0ab13a0e2..554e309267 100644 --- a/src/main/java/org/broadinstitute/consent/http/ConsentApplication.java +++ b/src/main/java/org/broadinstitute/consent/http/ConsentApplication.java @@ -84,6 +84,7 @@ import org.broadinstitute.consent.http.service.DatasetRegistrationService; import org.broadinstitute.consent.http.service.DatasetService; import org.broadinstitute.consent.http.service.DraftService; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; import org.broadinstitute.consent.http.service.ElasticSearchService; import org.broadinstitute.consent.http.service.ElectionService; import org.broadinstitute.consent.http.service.EmailService; diff --git a/src/main/java/org/broadinstitute/consent/http/ConsentModule.java b/src/main/java/org/broadinstitute/consent/http/ConsentModule.java index 776aeb3039..bb113eb2ab 100644 --- a/src/main/java/org/broadinstitute/consent/http/ConsentModule.java +++ b/src/main/java/org/broadinstitute/consent/http/ConsentModule.java @@ -44,8 +44,8 @@ import org.broadinstitute.consent.http.service.DataAccessRequestService; import org.broadinstitute.consent.http.service.DatasetRegistrationService; import org.broadinstitute.consent.http.service.DatasetService; -import org.broadinstitute.consent.http.service.DraftFileStorageService; -import org.broadinstitute.consent.http.service.DraftService; +import org.broadinstitute.consent.http.service.dao.DraftFileStorageServiceDAO; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; import org.broadinstitute.consent.http.service.ElasticSearchService; import org.broadinstitute.consent.http.service.ElectionService; import org.broadinstitute.consent.http.service.EmailService; @@ -628,14 +628,14 @@ DraftDAO providesDraftDAO() { } @Provides - DraftFileStorageService providesDraftFileStorageService() { - return new DraftFileStorageService(providesJdbi(), providesGCSService(), + DraftFileStorageServiceDAO providesDraftFileStorageService() { + return new DraftFileStorageServiceDAO(providesJdbi(), providesGCSService(), providesFileStorageObjectDAO()); } @Provides - DraftService providesDraftService() { - return new DraftService(providesJdbi(), providesDraftDAO(), + DraftServiceDAO providesDraftService() { + return new DraftServiceDAO(providesJdbi(), providesDraftDAO(), providesDraftFileStorageService()); } } diff --git a/src/main/java/org/broadinstitute/consent/http/service/DraftService.java b/src/main/java/org/broadinstitute/consent/http/service/DraftService.java index 950dfc7c2b..1bb7f3e992 100644 --- a/src/main/java/org/broadinstitute/consent/http/service/DraftService.java +++ b/src/main/java/org/broadinstitute/consent/http/service/DraftService.java @@ -2,173 +2,75 @@ import com.google.gson.Gson; import com.google.inject.Inject; -import jakarta.ws.rs.BadRequestException; -import jakarta.ws.rs.NotAuthorizedException; -import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.StreamingOutput; import java.io.InputStream; import java.sql.SQLException; -import java.util.Date; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.UUID; -import org.broadinstitute.consent.http.db.DraftDAO; -import org.broadinstitute.consent.http.enumeration.UserRoles; +import org.broadinstitute.consent.http.cloudstore.GCSService; import org.broadinstitute.consent.http.models.DraftInterface; import org.broadinstitute.consent.http.models.DraftSummary; import org.broadinstitute.consent.http.models.FileStorageObject; import org.broadinstitute.consent.http.models.User; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; +import org.broadinstitute.consent.http.util.ConsentLogger; import org.broadinstitute.consent.http.util.gson.GsonUtil; import org.glassfish.jersey.media.multipart.FormDataBodyPart; -import org.jdbi.v3.core.Jdbi; -public class DraftService { - - private final Jdbi jdbi; - private final DraftDAO draftDAO; - private final DraftFileStorageService draftFileStorageService; +public class DraftService implements ConsentLogger { + DraftServiceDAO draftServiceDAO; + GCSService gcsService; @Inject - public DraftService(Jdbi jdbi, DraftDAO draftDAO, - DraftFileStorageService draftFileStorageService) { - this.jdbi = jdbi; - this.draftDAO = draftDAO; - this.draftFileStorageService = draftFileStorageService; - } - - public void insertDraft(DraftInterface draft) - throws SQLException, BadRequestException { - jdbi.useHandle(handle -> { - handle.getConnection().setAutoCommit(false); - try { - draftDAO.insert(draft.getName(), draft.getCreateDate().toInstant(), - draft.getCreateUser().getUserId(), draft.getJson(), draft.getUUID(), - draft.getType().getValue()); - } catch (Exception e) { - handle.rollback(); - throw new BadRequestException( - "Error submitting draft. Drafts require valid json to be submitted."); - } - handle.commit(); - }); - } - - public DraftInterface updateDraft(DraftInterface draft, User user) throws SQLException { - draft.setUpdateUser(user); - draft.setUpdateDate(new Date()); - jdbi.useHandle(handle -> { - handle.getConnection().setAutoCommit(false); - try { - draftDAO.updateDraftByDraftUUID(draft.getName(), - draft.getUpdateDate().toInstant(), draft.getUpdateUser().getUserId(), draft.getJson(), - draft.getUUID(), draft.getType().getValue()); - } catch (Exception e) { - handle.rollback(); - } - handle.commit(); - }); - return getAuthorizedDraft(draft.getUUID(), user); + public DraftService(DraftServiceDAO draftServiceDAO, GCSService gcsService) { + this.draftServiceDAO = draftServiceDAO; + this.gcsService = gcsService; } - public DraftInterface getAuthorizedDraft(UUID draftUUID, User user) { - DraftInterface draft; - try { - draft = findDraftByDraftUUID(draftUUID); - } catch (SQLException e) { - throw new NotFoundException( - String.format("Draft with UUID %s not found.", draftUUID.toString())); - } - if (Objects.isNull(draft)) { - throw new NotFoundException( - String.format("Draft with UUID %s not found.", draftUUID.toString())); - } - if (!user.getUserId().equals(draft.getCreateUser().getUserId()) && !user.hasUserRole( - UserRoles.ADMIN)) { - throw new NotAuthorizedException("User not authorized to modify resource."); - } - return draft; + public DraftInterface getAuthorizedDraft(UUID uuid, User user) { + return draftServiceDAO.getAuthorizedDraft(uuid, user); } - public void deleteDraftsByUser(User user) { - Set userDrafts = findDraftsForUser(user); - for (DraftInterface draft : userDrafts) { - deleteDraft(draft, user); - } - } - - public Set findDraftSummariesForUser(User user) { - return draftDAO.findDraftSummariesByUserId(user.getUserId()); + public List addAttachments(DraftInterface draft, User user, Map files) + throws SQLException { + return draftServiceDAO.addAttachments(draft, user, files); } - public Set findDraftsForUser(User user) { - return draftDAO.findDraftsByUserId(user.getUserId()); + public InputStream getDraftAttachmentStream(FileStorageObject targetAttachment) { + return gcsService.getDocument(targetAttachment.getBlobId()); } - private DraftInterface findDraftByDraftUUID( - UUID draftUUID) throws SQLException { - return draftDAO.findDraftById(draftUUID); + public void deleteDraftAttachment(DraftInterface draft, User user, Integer fileId) + throws SQLException { + draftServiceDAO.deleteDraftAttachment(draft, user, fileId); } - public List addAttachments(DraftInterface draft, User user, - Map files) throws SQLException { - List storedFiles = draftFileStorageService.storeDraftFiles(draft.getUUID(), user, files); - draftDAO.updateDraftByDraftUUID(draft.getUUID(), - new Date().toInstant(), user.getUserId()); - return storedFiles; + public StreamingOutput draftAsJson(DraftInterface draft) { + Gson gson = GsonUtil.buildGson(); + return output -> { + output.write("{ \"document\":".getBytes()); + output.write(draft.getJson().getBytes()); + output.write(", \"meta\":".getBytes()); + output.write(gson.toJson(draft).getBytes()); + output.write("}".getBytes()); + }; } - public void deleteDraftAttachment(DraftInterface draft, User user, Integer fileId) - throws SQLException { - Optional fileStorageObjectToDelete = draft.getStoredFiles().stream() - .filter(fileStorageObject -> fileStorageObject.getFileStorageObjectId().equals(fileId)) - .findFirst(); - if (fileStorageObjectToDelete.isPresent()) { - draftFileStorageService.deleteStoredFile(fileStorageObjectToDelete.get(), user); - draftDAO.updateDraftByDraftUUID(draft.getUUID(), - new Date().toInstant(), user.getUserId()); - } else { - throw new NotFoundException( - String.format("Draft attachment is not found. Draft: %s, Attachment: %d", - draft.getUUID(), fileId)); - } + public void insertDraft(DraftInterface draft) throws SQLException { + draftServiceDAO.insertDraft(draft); } - public void deleteDraft(DraftInterface draft, User user) - throws RuntimeException { - jdbi.useHandle(handle -> { - try { - handle.useTransaction(handler -> { - draftDAO.deleteDraftByUUIDList(List.of(draft.getUUID())); - draft.getStoredFiles().forEach(fileStorageObject -> { - try { - draftFileStorageService.deleteStoredFile(fileStorageObject, user); - } catch (SQLException e) { - throw new RuntimeException(e); - } - }); - }); - } catch (Exception e) { - handle.rollback(); - } - handle.commit(); - }); + public Set findDraftSummariesForUser(User user) { + return draftServiceDAO.findDraftSummariesForUser(user); } - public StreamingOutput draftAsJson(DraftInterface draft) { - Gson gson = GsonUtil.buildGson(); - return output -> { - output.write("{ \"document\":".getBytes()); - output.write(draft.getJson().getBytes()); - output.write(", \"meta\":".getBytes()); - output.write(gson.toJson(draft).getBytes()); - output.write("}".getBytes()); - }; + public DraftInterface updateDraft(DraftInterface draft, User user) throws SQLException { + return draftServiceDAO.updateDraft(draft, user); } - public InputStream getDraftAttachmentStream(FileStorageObject targetAttachment) { - return draftFileStorageService.get(targetAttachment); + public void deleteDraft(DraftInterface draft, User user) { + draftServiceDAO.deleteDraft(draft, user); } } diff --git a/src/main/java/org/broadinstitute/consent/http/service/UserService.java b/src/main/java/org/broadinstitute/consent/http/service/UserService.java index 5be01bc6d1..60904c147f 100644 --- a/src/main/java/org/broadinstitute/consent/http/service/UserService.java +++ b/src/main/java/org/broadinstitute/consent/http/service/UserService.java @@ -39,6 +39,7 @@ import org.broadinstitute.consent.http.models.UserUpdateFields; import org.broadinstitute.consent.http.models.Vote; import org.broadinstitute.consent.http.resources.Resource; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; import org.broadinstitute.consent.http.service.dao.UserServiceDAO; import org.broadinstitute.consent.http.util.ConsentLogger; import org.broadinstitute.consent.http.util.gson.GsonUtil; @@ -61,14 +62,14 @@ public class UserService implements ConsentLogger { private final UserServiceDAO userServiceDAO; private final DaaDAO daaDAO; private final EmailService emailService; - private final DraftService draftService; + private final DraftServiceDAO draftServiceDAO; @Inject public UserService(UserDAO userDAO, UserPropertyDAO userPropertyDAO, UserRoleDAO userRoleDAO, VoteDAO voteDAO, InstitutionDAO institutionDAO, LibraryCardDAO libraryCardDAO, AcknowledgementDAO acknowledgementDAO, FileStorageObjectDAO fileStorageObjectDAO, SamDAO samDAO, UserServiceDAO userServiceDAO, DaaDAO daaDAO, EmailService emailService, - DraftService draftService) { + DraftServiceDAO draftServiceDAO) { this.userDAO = userDAO; this.userPropertyDAO = userPropertyDAO; this.userRoleDAO = userRoleDAO; @@ -81,7 +82,7 @@ public UserService(UserDAO userDAO, UserPropertyDAO userPropertyDAO, UserRoleDAO this.userServiceDAO = userServiceDAO; this.daaDAO = daaDAO; this.emailService = emailService; - this.draftService = draftService; + this.draftServiceDAO = draftServiceDAO; } /** @@ -268,7 +269,7 @@ public void deleteUserByEmail(String email) { List voteIds = votes.stream().map(Vote::getVoteId).collect(Collectors.toList()); voteDAO.removeVotesByIds(voteIds); } - draftService.deleteDraftsByUser(user); + draftServiceDAO.deleteDraftsByUser(user); institutionDAO.deleteAllInstitutionsByUser(userId); userPropertyDAO.deleteAllPropertiesByUser(userId); libraryCardDAO.deleteAllLibraryCardsByUser(userId); diff --git a/src/main/java/org/broadinstitute/consent/http/service/DraftFileStorageService.java b/src/main/java/org/broadinstitute/consent/http/service/dao/DraftFileStorageServiceDAO.java similarity index 92% rename from src/main/java/org/broadinstitute/consent/http/service/DraftFileStorageService.java rename to src/main/java/org/broadinstitute/consent/http/service/dao/DraftFileStorageServiceDAO.java index 390acba482..3c8486c00a 100644 --- a/src/main/java/org/broadinstitute/consent/http/service/DraftFileStorageService.java +++ b/src/main/java/org/broadinstitute/consent/http/service/dao/DraftFileStorageServiceDAO.java @@ -1,4 +1,4 @@ -package org.broadinstitute.consent.http.service; +package org.broadinstitute.consent.http.service.dao; import com.google.cloud.storage.BlobId; import com.google.inject.Inject; @@ -20,14 +20,14 @@ import org.glassfish.jersey.media.multipart.FormDataBodyPart; import org.jdbi.v3.core.Jdbi; -public class DraftFileStorageService implements ConsentLogger { +public class DraftFileStorageServiceDAO implements ConsentLogger { Jdbi jdbi; GCSService gcsService; FileStorageObjectDAO fileStorageObjectDAO; @Inject - public DraftFileStorageService(Jdbi jdbi, GCSService gcsService, + public DraftFileStorageServiceDAO(Jdbi jdbi, GCSService gcsService, FileStorageObjectDAO fileStorageObjectDAO) { this.jdbi = jdbi; this.gcsService = gcsService; @@ -107,8 +107,4 @@ private FileStorageObject store(FormDataBodyPart file, User user, UUID draftId) throw new RuntimeException(e); } } - - public InputStream get(FileStorageObject fileStorageObject) { - return gcsService.getDocument(fileStorageObject.getBlobId()); - } } diff --git a/src/main/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAO.java b/src/main/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAO.java new file mode 100644 index 0000000000..58078e503b --- /dev/null +++ b/src/main/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAO.java @@ -0,0 +1,156 @@ +package org.broadinstitute.consent.http.service.dao; + +import com.google.inject.Inject; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.NotAuthorizedException; +import jakarta.ws.rs.NotFoundException; +import java.sql.SQLException; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import org.broadinstitute.consent.http.db.DraftDAO; +import org.broadinstitute.consent.http.enumeration.UserRoles; +import org.broadinstitute.consent.http.models.DraftInterface; +import org.broadinstitute.consent.http.models.DraftSummary; +import org.broadinstitute.consent.http.models.FileStorageObject; +import org.broadinstitute.consent.http.models.User; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.jdbi.v3.core.Jdbi; + +public class DraftServiceDAO { + + private final Jdbi jdbi; + private final DraftDAO draftDAO; + private final DraftFileStorageServiceDAO draftFileStorageServiceDAO; + + @Inject + public DraftServiceDAO(Jdbi jdbi, DraftDAO draftDAO, + DraftFileStorageServiceDAO draftFileStorageServiceDAO) { + this.jdbi = jdbi; + this.draftDAO = draftDAO; + this.draftFileStorageServiceDAO = draftFileStorageServiceDAO; + } + + public void insertDraft(DraftInterface draft) + throws SQLException, BadRequestException { + jdbi.useHandle(handle -> { + handle.getConnection().setAutoCommit(false); + try { + draftDAO.insert(draft.getName(), draft.getCreateDate().toInstant(), + draft.getCreateUser().getUserId(), draft.getJson(), draft.getUUID(), + draft.getType().getValue()); + } catch (Exception e) { + handle.rollback(); + throw new BadRequestException( + "Error submitting draft. Drafts require valid json to be submitted."); + } + handle.commit(); + }); + } + + public DraftInterface updateDraft(DraftInterface draft, User user) throws SQLException { + draft.setUpdateUser(user); + draft.setUpdateDate(new Date()); + jdbi.useHandle(handle -> { + handle.getConnection().setAutoCommit(false); + try { + draftDAO.updateDraftByDraftUUID(draft.getName(), + draft.getUpdateDate().toInstant(), draft.getUpdateUser().getUserId(), draft.getJson(), + draft.getUUID(), draft.getType().getValue()); + } catch (Exception e) { + handle.rollback(); + } + handle.commit(); + }); + return getAuthorizedDraft(draft.getUUID(), user); + } + + public DraftInterface getAuthorizedDraft(UUID draftUUID, User user) { + DraftInterface draft; + try { + draft = findDraftByDraftUUID(draftUUID); + } catch (SQLException e) { + throw new NotFoundException( + String.format("Draft with UUID %s not found.", draftUUID.toString())); + } + if (Objects.isNull(draft)) { + throw new NotFoundException( + String.format("Draft with UUID %s not found.", draftUUID.toString())); + } + if (!user.getUserId().equals(draft.getCreateUser().getUserId()) && !user.hasUserRole( + UserRoles.ADMIN)) { + throw new NotAuthorizedException("User not authorized to modify resource."); + } + return draft; + } + + public void deleteDraftsByUser(User user) { + Set userDrafts = findDraftsForUser(user); + for (DraftInterface draft : userDrafts) { + deleteDraft(draft, user); + } + } + + public Set findDraftSummariesForUser(User user) { + return draftDAO.findDraftSummariesByUserId(user.getUserId()); + } + + public Set findDraftsForUser(User user) { + return draftDAO.findDraftsByUserId(user.getUserId()); + } + + private DraftInterface findDraftByDraftUUID( + UUID draftUUID) throws SQLException { + return draftDAO.findDraftById(draftUUID); + } + + public List addAttachments(DraftInterface draft, User user, + Map files) throws SQLException { + List storedFiles = draftFileStorageServiceDAO.storeDraftFiles(draft.getUUID(), user, files); + draftDAO.updateDraftByDraftUUID(draft.getUUID(), + new Date().toInstant(), user.getUserId()); + return storedFiles; + } + + public void deleteDraftAttachment(DraftInterface draft, User user, Integer fileId) + throws SQLException { + Optional fileStorageObjectToDelete = draft.getStoredFiles().stream() + .filter(fileStorageObject -> fileStorageObject.getFileStorageObjectId().equals(fileId)) + .findFirst(); + if (fileStorageObjectToDelete.isPresent()) { + draftFileStorageServiceDAO.deleteStoredFile(fileStorageObjectToDelete.get(), user); + draftDAO.updateDraftByDraftUUID(draft.getUUID(), + new Date().toInstant(), user.getUserId()); + } else { + throw new NotFoundException( + String.format("Draft attachment is not found. Draft: %s, Attachment: %d", + draft.getUUID(), fileId)); + } + } + + public void deleteDraft(DraftInterface draft, User user) + throws RuntimeException { + jdbi.useHandle(handle -> { + try { + handle.useTransaction(handler -> { + draftDAO.deleteDraftByUUIDList(List.of(draft.getUUID())); + draft.getStoredFiles().forEach(fileStorageObject -> { + try { + draftFileStorageServiceDAO.deleteStoredFile(fileStorageObject, user); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }); + }); + } catch (Exception e) { + handle.rollback(); + throw new RuntimeException(e); + } + handle.commit(); + }); + } +} diff --git a/src/test/java/org/broadinstitute/consent/http/resources/DraftResourceTest.java b/src/test/java/org/broadinstitute/consent/http/resources/DraftResourceTest.java index 745d1cda38..baa488e90c 100644 --- a/src/test/java/org/broadinstitute/consent/http/resources/DraftResourceTest.java +++ b/src/test/java/org/broadinstitute/consent/http/resources/DraftResourceTest.java @@ -34,6 +34,7 @@ import org.broadinstitute.consent.http.models.FileStorageObject; import org.broadinstitute.consent.http.models.User; import org.broadinstitute.consent.http.service.DraftService; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; import org.broadinstitute.consent.http.service.UserService; import org.glassfish.jersey.media.multipart.FormDataMultiPart; import org.junit.jupiter.api.Test; @@ -59,12 +60,6 @@ class DraftResourceTest { @Mock private UserService userService; - @Mock - private UriInfo uriInfo; - - @Mock - private UriBuilder uriBuilder; - private DraftResource resource; private void initResource() { diff --git a/src/test/java/org/broadinstitute/consent/http/service/DraftServiceTest.java b/src/test/java/org/broadinstitute/consent/http/service/DraftServiceTest.java index 2e401da245..631182eb8f 100644 --- a/src/test/java/org/broadinstitute/consent/http/service/DraftServiceTest.java +++ b/src/test/java/org/broadinstitute/consent/http/service/DraftServiceTest.java @@ -1,225 +1,78 @@ package org.broadinstitute.consent.http.service; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.when; import com.google.cloud.storage.BlobId; import com.google.gson.Gson; import jakarta.ws.rs.BadRequestException; -import jakarta.ws.rs.NotAuthorizedException; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.StreamingOutput; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.sql.SQLException; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.UUID; -import java.util.stream.IntStream; import org.broadinstitute.consent.http.cloudstore.GCSService; -import org.broadinstitute.consent.http.db.DAOTestHelper; -import org.broadinstitute.consent.http.enumeration.UserRoles; -import org.broadinstitute.consent.http.models.DraftInterface; import org.broadinstitute.consent.http.models.DraftStudyDataset; import org.broadinstitute.consent.http.models.FileStorageObject; import org.broadinstitute.consent.http.models.User; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; import org.broadinstitute.consent.http.util.gson.GsonUtil; -import org.glassfish.jersey.media.multipart.FormDataBodyPart; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class DraftServiceTest extends DAOTestHelper { - @Mock - GCSService gcsService; - private DraftService draftService; - - @BeforeEach - void setup() throws IOException { - DraftFileStorageService draftFileStorageService = new DraftFileStorageService(jdbi, gcsService, - fileStorageObjectDAO); - this.draftService = new DraftService(jdbi, draftDAO, - draftFileStorageService); - } - - @Test - void testCreateDraft() throws SQLException, IOException { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User user = createUser(); - DraftInterface draft = createDraft(user, 3); - assertThat(draftDAO.findDraftsByUserId(user.getUserId()), hasSize(1)); - Set storedDrafts = draftDAO.findDraftsByUserId( - user.getUserId()); - assertThat(storedDrafts, hasSize(1)); - DraftInterface storedDraft = storedDrafts.iterator().next(); - assertThat(storedDraft.getStoredFiles(), hasSize(3)); - assertEquals(storedDraft.getUUID(), draft.getUUID()); - } +public class DraftServiceTest { - @Test - void testCreateDraftWithInvalidJson() { - User user = createUser(); - DraftStudyDataset draft = new DraftStudyDataset("Hello world!",user); - assertThrows(BadRequestException.class, ()-> draftService.insertDraft(draft)); - } - - @Test - void testThinUserIsReturnedFromDraft() throws SQLException, IOException { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User user = createUser(); - DraftInterface draft = createDraft(user, 3); - assertThat(user.getRoles(), hasSize(greaterThan(0))); - assertThinUser(draft.getCreateUser()); - assertThinUser(draft.getUpdateUser()); - } - - @Test - void testGetAuthorizedDraft() throws SQLException, IOException { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User goodUser = createUser(); - User badUser = createUser(); - User adminUser = createUser(); - adminUser.addRole(UserRoles.Admin()); - DraftInterface draft = createDraft(goodUser, 4); - assertThat(draftDAO.findDraftsByUserId(goodUser.getUserId()), hasSize(1)); - assertThrows(NotFoundException.class, - () -> draftService.getAuthorizedDraft(UUID.randomUUID(), goodUser)); - assertThrows(NotAuthorizedException.class, - () -> draftService.getAuthorizedDraft(draft.getUUID(), badUser)); - assertThat(draftDAO.findDraftsByUserId(adminUser.getUserId()), hasSize(0)); - DraftInterface adminVisibleDraft = draftService.getAuthorizedDraft( - draft.getUUID(), adminUser); - assertEquals(adminVisibleDraft.getUUID(), draft.getUUID()); - assertEquals(adminVisibleDraft.getName(), draft.getName()); - assertThat(adminVisibleDraft.getStoredFiles(), hasSize(4)); - } - - @Test - void testDeleteDraft() throws Exception { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User user = createUser(); - createDraft(user, 3); - Set loadedDrafts = draftDAO.findDraftsByUserId( - user.getUserId()); - assertThat(loadedDrafts, hasSize(1)); - draftService.deleteDraft(loadedDrafts.iterator().next(), user); - assertThat(draftDAO.findDraftsByUserId(user.getUserId()), hasSize(0)); - } - - @Test - void testDeleteDraftsForUser() throws SQLException, IOException { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User user = createUser(); - User user2 = createUser(); - createDraft(user, 3); - createDraft(user2, 1); - createDraft(user2, 4); - assertThat(draftService.findDraftsForUser(user2), hasSize(2)); - assertThat(draftService.findDraftsForUser(user), hasSize(1)); - draftService.deleteDraftsByUser(user2); - assertThat(draftService.findDraftsForUser(user), hasSize(1)); - assertThat(draftService.findDraftsForUser(user2), hasSize(0)); - draftService.deleteDraftsByUser(user2); - } + @Mock + private DraftServiceDAO draftServiceDAO; - @Test - void testAddAttachmentToDraft() throws SQLException, IOException { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User user = createUser(); - DraftInterface draft = createDraft(user, 3); - Map files = getRandomFiles(1); - List addedAttachments = draftService.addAttachments(draft, user, files); - assertThat(addedAttachments, hasSize(1)); - DraftInterface updatedDraft = draftService.getAuthorizedDraft(draft.getUUID(), user); - assertThat(updatedDraft.getStoredFiles(), hasSize(4)); - } + @Mock + private GCSService gcsService; @Test - void testDeleteAttachmentFromDraft() throws SQLException, IOException { - when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( - BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - User user = createUser(); - DraftInterface draft = createDraft(user, 3); - Set storedFiles = draft.getStoredFiles(); - assertThat(storedFiles, hasSize(3)); - for (FileStorageObject file : storedFiles) { - draftService.deleteDraftAttachment(draft, user, file.getFileStorageObjectId()); - } - assertThat(draftService.getAuthorizedDraft(draft.getUUID(), user).getStoredFiles(), - hasSize(0)); + public void testCreateDraft() throws SQLException { + doThrow(new BadRequestException("Bad Request")).when(draftServiceDAO).insertDraft(any()); + DraftService draftService = new DraftService(draftServiceDAO, gcsService); + assertThrows(BadRequestException.class, ()-> draftService.insertDraft(null)); } @Test - void testStreamingOutput() throws SQLException, IOException { - User user = createUser(); - DraftInterface draft = createDraft(user, 1); - StreamingOutput output = draftService.draftAsJson(draft); + public void testStreamingOutput() throws SQLException, IOException { + DraftService draftService = new DraftService(draftServiceDAO, gcsService); + User user = new User(); + user.setEmail("test@test.com"); + user.setUserId(1); + DraftStudyDataset studyDataset = new DraftStudyDataset("{}", user); + StreamingOutput output = draftService.draftAsJson(studyDataset); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); output.write(byteArrayOutputStream); byteArrayOutputStream.close(); Gson gson = GsonUtil.buildGson(); StreamingDeserializer streamedData = gson.fromJson(byteArrayOutputStream.toString(), StreamingDeserializer.class); - assertEquals(draft.getCreateDate().getTime(), streamedData.meta.getCreateDate().getTime()); + assertEquals(studyDataset.getCreateDate().getTime(), streamedData.meta.getCreateDate().getTime()); assertEquals("{}", streamedData.document.toString()); } @Test - void testUpdateDraft() throws SQLException { - User user = createUser(); - DraftInterface draft = createDraft(user, 1); - String updatedJson = "{\"study\": \"My example study\"}"; - String newDraftName = "My favorite draft"; - String originalDocumentJson = draft.getJson(); - Date originalDocumentDate = draft.getUpdateDate(); - assertEquals(originalDocumentJson, draft.getJson()); - assertEquals(originalDocumentDate, draft.getUpdateDate()); - assertNotEquals(draft.getName(), newDraftName); - draft.setName(newDraftName); - draft.setJson(updatedJson); - DraftInterface updatedDraft = draftService.updateDraft(draft, user); - assertEquals(draft.getUUID(), updatedDraft.getUUID()); - assertEquals(newDraftName, updatedDraft.getName()); - assertEquals(updatedJson, updatedDraft.getJson()); - assertThinUser(updatedDraft.getCreateUser()); - assertThinUser(updatedDraft.getUpdateUser()); - } - - @NotNull - private DraftInterface createDraft(User user, Integer numberOfFiles) - throws SQLException { - DraftStudyDataset draft = new DraftStudyDataset("{}", user); - draftService.insertDraft(draft); - Map mapOfFiles = getRandomFiles(numberOfFiles); - draftService.addAttachments(draft, user, mapOfFiles); - return draftService.getAuthorizedDraft(draft.getUUID(), user); + void testGetDraftFile() throws IOException, SQLException { + when(gcsService.getDocument((BlobId) any())) + .thenAnswer(inputStream -> new ByteArrayInputStream("{}".getBytes(StandardCharsets.UTF_8)) { + }); + DraftService draftService = new DraftService(draftServiceDAO, gcsService); + FileStorageObject fileStorageObject = new FileStorageObject(); + fileStorageObject.setBlobId(BlobId.of(UUID.randomUUID().toString(), "test")); + InputStream fileContents = draftService.getDraftAttachmentStream(fileStorageObject); + assertEquals("{}", + new String(fileContents.readAllBytes(), StandardCharsets.UTF_8)); } private static class StreamingDeserializer { @@ -232,32 +85,4 @@ public StreamingDeserializer(String document, DraftStudyDataset meta) { this.meta = meta; } } - - private void assertThinUser(User user) { - assertThat(user.getRoles(), is(nullValue())); - assertThat(user.getUserId(), is(notNullValue())); - assertThat(user.getInstitutionId(), is(nullValue())); - assertThat(user.getEraCommonsId(), is(nullValue())); - } - - private Map getRandomFiles(Integer count) { - Map mapOfFiles = new HashMap<>(); - IntStream.range(0, count) - .forEach(index -> { - String name = String.format("file%d", index); - mapOfFiles.put(name, getFormDataBodyPartMock(name)); - }); - return mapOfFiles; - } - - private FormDataBodyPart getFormDataBodyPartMock(String name) { - FormDataBodyPart part = mock(FormDataBodyPart.class); - when(part.getName()).thenReturn(name); - when(part.getMediaType()).thenReturn(MediaType.MULTIPART_FORM_DATA_TYPE); - when(part.getValueAs(InputStream.class)) - .thenReturn(new ByteArrayInputStream(EMPTY_JSON_DOCUMENT.getBytes())); - return part; - } - - -} +} \ No newline at end of file diff --git a/src/test/java/org/broadinstitute/consent/http/service/UserServiceTest.java b/src/test/java/org/broadinstitute/consent/http/service/UserServiceTest.java index 18ae8032cb..fcfa0c18e0 100644 --- a/src/test/java/org/broadinstitute/consent/http/service/UserServiceTest.java +++ b/src/test/java/org/broadinstitute/consent/http/service/UserServiceTest.java @@ -48,6 +48,7 @@ import org.broadinstitute.consent.http.models.sam.UserStatus; import org.broadinstitute.consent.http.models.sam.UserStatusInfo; import org.broadinstitute.consent.http.service.UserService.SimplifiedUser; +import org.broadinstitute.consent.http.service.dao.DraftServiceDAO; import org.broadinstitute.consent.http.service.dao.UserServiceDAO; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -95,7 +96,7 @@ class UserServiceTest { private EmailService emailService; @Mock - private DraftService draftService; + private DraftServiceDAO draftServiceDAO; private UserService service; @@ -103,7 +104,7 @@ class UserServiceTest { private void initService() { service = new UserService(userDAO, userPropertyDAO, userRoleDAO, voteDAO, institutionDAO, libraryCardDAO, acknowledgementDAO, fileStorageObjectDAO, samDAO, userServiceDAO, daaDAO, - emailService, draftService); + emailService, draftServiceDAO); } @Test diff --git a/src/test/java/org/broadinstitute/consent/http/service/DraftFileStorageServiceTest.java b/src/test/java/org/broadinstitute/consent/http/service/dao/DraftFileStorageServiceDAOTest.java similarity index 73% rename from src/test/java/org/broadinstitute/consent/http/service/DraftFileStorageServiceTest.java rename to src/test/java/org/broadinstitute/consent/http/service/dao/DraftFileStorageServiceDAOTest.java index 29e4f721b6..726ef9925b 100644 --- a/src/test/java/org/broadinstitute/consent/http/service/DraftFileStorageServiceTest.java +++ b/src/test/java/org/broadinstitute/consent/http/service/dao/DraftFileStorageServiceDAOTest.java @@ -1,4 +1,4 @@ -package org.broadinstitute.consent.http.service; +package org.broadinstitute.consent.http.service.dao; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasKey; @@ -37,17 +37,17 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class DraftFileStorageServiceTest extends DAOTestHelper { +class DraftFileStorageServiceDAOTest extends DAOTestHelper { @Mock private GCSService gcsService; - private DraftFileStorageService draftFileStorageService; + private DraftFileStorageServiceDAO draftFileStorageServiceDAO; @BeforeEach void setUp() throws IOException { when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); - draftFileStorageService = new DraftFileStorageService(jdbi, gcsService, fileStorageObjectDAO); + draftFileStorageServiceDAO = new DraftFileStorageServiceDAO(jdbi, gcsService, fileStorageObjectDAO); } @Test @@ -55,7 +55,7 @@ void testCreateDraftFile() throws SQLException { User user = createUser(); UUID associatedUUID = UUID.randomUUID(); Map testFiles = getRandomFiles(4); - List storedFiles = draftFileStorageService.storeDraftFiles(associatedUUID, + List storedFiles = draftFileStorageServiceDAO.storeDraftFiles(associatedUUID, user, testFiles); assertThat(testFiles.values(), hasSize(4)); assertThat(storedFiles, hasSize(4)); @@ -72,34 +72,15 @@ void testDeleteDraftFiles() throws SQLException { User user = createUser(); UUID associatedUUID = UUID.randomUUID(); Map testFiles = getRandomFiles(2); - List storedFiles = draftFileStorageService.storeDraftFiles(associatedUUID, + List storedFiles = draftFileStorageServiceDAO.storeDraftFiles(associatedUUID, user, testFiles); assertThat(testFiles.values(), hasSize(2)); assertThat(storedFiles, hasSize(2)); for (FileStorageObject fileStorageObject : storedFiles) { - draftFileStorageService.deleteStoredFile(fileStorageObject, user); + draftFileStorageServiceDAO.deleteStoredFile(fileStorageObject, user); } assertThrows(NotFoundException.class, - () -> draftFileStorageService.deleteStoredFile(new FileStorageObject(), user)); - } - - @Test - void testGetDraftFile() throws IOException, SQLException { - when(gcsService.getDocument((BlobId) any())) - .thenAnswer(inputStream -> new ByteArrayInputStream("{}".getBytes(StandardCharsets.UTF_8)) { - }); - User user = createUser(); - UUID associatedUUID = UUID.randomUUID(); - Map testFiles = getRandomFiles(2); - List storedFiles = draftFileStorageService.storeDraftFiles(associatedUUID, - user, testFiles); - assertThat(testFiles.values(), hasSize(2)); - assertThat(storedFiles, hasSize(2)); - for (FileStorageObject fileStorageObject : storedFiles) { - InputStream fileContents = draftFileStorageService.get(fileStorageObject); - assertEquals(EMPTY_JSON_DOCUMENT, - new String(fileContents.readAllBytes(), StandardCharsets.UTF_8)); - } + () -> draftFileStorageServiceDAO.deleteStoredFile(new FileStorageObject(), user)); } private Map getRandomFiles(Integer count) { diff --git a/src/test/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAOTest.java b/src/test/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAOTest.java new file mode 100644 index 0000000000..3fb888ae45 --- /dev/null +++ b/src/test/java/org/broadinstitute/consent/http/service/dao/DraftServiceDAOTest.java @@ -0,0 +1,242 @@ +package org.broadinstitute.consent.http.service.dao; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.cloud.storage.BlobId; +import com.google.gson.Gson; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.NotAuthorizedException; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.StreamingOutput; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.IntStream; +import org.broadinstitute.consent.http.cloudstore.GCSService; +import org.broadinstitute.consent.http.db.DAOTestHelper; +import org.broadinstitute.consent.http.enumeration.UserRoles; +import org.broadinstitute.consent.http.models.DraftInterface; +import org.broadinstitute.consent.http.models.DraftStudyDataset; +import org.broadinstitute.consent.http.models.FileStorageObject; +import org.broadinstitute.consent.http.models.User; +import org.broadinstitute.consent.http.util.gson.GsonUtil; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.jdbi.v3.core.statement.StatementException; +import org.jdbi.v3.core.statement.UnableToExecuteStatementException; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class DraftServiceDAOTest extends DAOTestHelper { + @Mock + GCSService gcsService; + + private DraftServiceDAO draftServiceDAO; + + @BeforeEach + void setup() throws IOException { + DraftFileStorageServiceDAO draftFileStorageServiceDAO = new DraftFileStorageServiceDAO(jdbi, gcsService, + fileStorageObjectDAO); + this.draftServiceDAO = new DraftServiceDAO(jdbi, draftDAO, + draftFileStorageServiceDAO); + } + + @Test + void testCreateDraft() throws SQLException, IOException { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User user = createUser(); + DraftInterface draft = createDraft(user, 3); + assertThat(draftDAO.findDraftsByUserId(user.getUserId()), hasSize(1)); + Set storedDrafts = draftDAO.findDraftsByUserId( + user.getUserId()); + assertThat(storedDrafts, hasSize(1)); + DraftInterface storedDraft = storedDrafts.iterator().next(); + assertThat(storedDraft.getStoredFiles(), hasSize(3)); + assertEquals(storedDraft.getUUID(), draft.getUUID()); + } + + @Test + void testCreateDraftWithInvalidJson() { + User user = createUser(); + DraftStudyDataset draft = new DraftStudyDataset("Hello world!",user); + assertThrows(BadRequestException.class, ()-> draftServiceDAO.insertDraft(draft)); + } + + @Test + void testThinUserIsReturnedFromDraft() throws SQLException, IOException { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User user = createUser(); + DraftInterface draft = createDraft(user, 3); + assertThat(user.getRoles(), hasSize(greaterThan(0))); + assertThinUser(draft.getCreateUser()); + assertThinUser(draft.getUpdateUser()); + } + + @Test + void testGetAuthorizedDraft() throws SQLException, IOException { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User goodUser = createUser(); + User badUser = createUser(); + User adminUser = createUser(); + adminUser.addRole(UserRoles.Admin()); + DraftInterface draft = createDraft(goodUser, 4); + assertThat(draftDAO.findDraftsByUserId(goodUser.getUserId()), hasSize(1)); + assertThrows(NotFoundException.class, + () -> draftServiceDAO.getAuthorizedDraft(UUID.randomUUID(), goodUser)); + assertThrows(NotAuthorizedException.class, + () -> draftServiceDAO.getAuthorizedDraft(draft.getUUID(), badUser)); + assertThat(draftDAO.findDraftsByUserId(adminUser.getUserId()), hasSize(0)); + DraftInterface adminVisibleDraft = draftServiceDAO.getAuthorizedDraft( + draft.getUUID(), adminUser); + assertEquals(adminVisibleDraft.getUUID(), draft.getUUID()); + assertEquals(adminVisibleDraft.getName(), draft.getName()); + assertThat(adminVisibleDraft.getStoredFiles(), hasSize(4)); + } + + @Test + void testDeleteDraft() throws Exception { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User user = createUser(); + createDraft(user, 3); + Set loadedDrafts = draftDAO.findDraftsByUserId( + user.getUserId()); + assertThat(loadedDrafts, hasSize(1)); + draftServiceDAO.deleteDraft(loadedDrafts.iterator().next(), user); + assertThat(draftDAO.findDraftsByUserId(user.getUserId()), hasSize(0)); + } + + @Test + void testDeleteDraftsForUser() throws SQLException, IOException { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User user = createUser(); + User user2 = createUser(); + createDraft(user, 3); + createDraft(user2, 1); + createDraft(user2, 4); + assertThat(draftServiceDAO.findDraftsForUser(user2), hasSize(2)); + assertThat(draftServiceDAO.findDraftsForUser(user), hasSize(1)); + draftServiceDAO.deleteDraftsByUser(user2); + assertThat(draftServiceDAO.findDraftsForUser(user), hasSize(1)); + assertThat(draftServiceDAO.findDraftsForUser(user2), hasSize(0)); + draftServiceDAO.deleteDraftsByUser(user2); + } + + @Test + void testAddAttachmentToDraft() throws SQLException, IOException { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User user = createUser(); + DraftInterface draft = createDraft(user, 3); + Map files = getRandomFiles(1); + List addedAttachments = draftServiceDAO.addAttachments(draft, user, files); + assertThat(addedAttachments, hasSize(1)); + DraftInterface updatedDraft = draftServiceDAO.getAuthorizedDraft(draft.getUUID(), user); + assertThat(updatedDraft.getStoredFiles(), hasSize(4)); + } + + @Test + void testDeleteAttachmentFromDraft() throws SQLException, IOException { + when(gcsService.storeDocument(any(), anyString(), any())).thenReturn( + BlobId.of(UUID.randomUUID().toString(), UUID.randomUUID().toString())); + User user = createUser(); + DraftInterface draft = createDraft(user, 3); + Set storedFiles = draft.getStoredFiles(); + assertThat(storedFiles, hasSize(3)); + for (FileStorageObject file : storedFiles) { + draftServiceDAO.deleteDraftAttachment(draft, user, file.getFileStorageObjectId()); + } + assertThat(draftServiceDAO.getAuthorizedDraft(draft.getUUID(), user).getStoredFiles(), + hasSize(0)); + } + + + + @Test + void testUpdateDraft() throws SQLException { + User user = createUser(); + DraftInterface draft = createDraft(user, 1); + String updatedJson = "{\"study\": \"My example study\"}"; + String newDraftName = "My favorite draft"; + String originalDocumentJson = draft.getJson(); + Date originalDocumentDate = draft.getUpdateDate(); + assertEquals(originalDocumentJson, draft.getJson()); + assertEquals(originalDocumentDate, draft.getUpdateDate()); + assertNotEquals(draft.getName(), newDraftName); + draft.setName(newDraftName); + draft.setJson(updatedJson); + DraftInterface updatedDraft = draftServiceDAO.updateDraft(draft, user); + assertEquals(draft.getUUID(), updatedDraft.getUUID()); + assertEquals(newDraftName, updatedDraft.getName()); + assertEquals(updatedJson, updatedDraft.getJson()); + assertThinUser(updatedDraft.getCreateUser()); + assertThinUser(updatedDraft.getUpdateUser()); + } + + @NotNull + private DraftInterface createDraft(User user, Integer numberOfFiles) + throws SQLException { + DraftStudyDataset draft = new DraftStudyDataset("{}", user); + draftServiceDAO.insertDraft(draft); + Map mapOfFiles = getRandomFiles(numberOfFiles); + draftServiceDAO.addAttachments(draft, user, mapOfFiles); + return draftServiceDAO.getAuthorizedDraft(draft.getUUID(), user); + } + + private void assertThinUser(User user) { + assertThat(user.getRoles(), is(nullValue())); + assertThat(user.getUserId(), is(notNullValue())); + assertThat(user.getInstitutionId(), is(nullValue())); + assertThat(user.getEraCommonsId(), is(nullValue())); + } + + private Map getRandomFiles(Integer count) { + Map mapOfFiles = new HashMap<>(); + IntStream.range(0, count) + .forEach(index -> { + String name = String.format("file%d", index); + mapOfFiles.put(name, getFormDataBodyPartMock(name)); + }); + return mapOfFiles; + } + + private FormDataBodyPart getFormDataBodyPartMock(String name) { + FormDataBodyPart part = mock(FormDataBodyPart.class); + when(part.getName()).thenReturn(name); + when(part.getMediaType()).thenReturn(MediaType.MULTIPART_FORM_DATA_TYPE); + when(part.getValueAs(InputStream.class)) + .thenReturn(new ByteArrayInputStream(EMPTY_JSON_DOCUMENT.getBytes())); + return part; + } + + +}