diff --git a/CHANGELOG.md b/CHANGELOG.md index 154ad5577dc..b6259bac6e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * [Developer]: Added support for cloud based storage. Currently, Microsoft Azure Blob and Amazon AWS S3 are supported. [See PR 1194](https://github.com/phac-nml/irida/pull/1194) * [Developer]: Updated metadata uploader to use react-router-dom Outlet. [See PR 1464](https://github.com/phac-nml/irida/pull/1464) * [Developer]: Deprecated "/api/projects/{projectId}/samples/bySequencerId/{seqeuncerId}" in favour of "/api/projects/{projectId}/samples/bySampleName", which accepts a json property "sampleName" +* [Developer]: Fixed bug in setting a `default_sequencing_object and default_genome_assembly to `NULL` for a sample when the default sequencing object or genome assembly were removed. [See PR 1466](https://github.com/phac-nml/irida/pull/1466) ## [22.09.7] - 2022/01/24 * [UI]: Fixed bugs on NCBI Export page preventing the NCBI `submission.xml` file from being properly written. See [PR 1451](https://github.com/phac-nml/irida/pull/1451) diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryCustom.java b/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryCustom.java index 5c85020999b..65d69d4806d 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryCustom.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryCustom.java @@ -16,4 +16,18 @@ public interface SampleRepositoryCustom { * @param modifiedDate The new {@link Date} */ void updateSampleModifiedDate(Sample sample, Date modifiedDate); + + /** + * Update the default sequencing object in a {@link Sample} to NULL. + * + * @param sample The {@link Sample} to update + */ + void removeDefaultSequencingObject(Sample sample); + + /** + * Update the default genome assembly in a {@link Sample} to NULL. + * + * @param sample The {@link Sample} to update + */ + void removeDefaultGenomeAssembly(Sample sample); } diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryImpl.java b/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryImpl.java index b0dda4605d7..8f041bf980c 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryImpl.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/repositories/sample/SampleRepositoryImpl.java @@ -31,4 +31,19 @@ public void updateSampleModifiedDate(Sample sample, Date modifiedDate) { query.setParameter(2, sample.getId()); query.executeUpdate(); } + + @Transactional + public void removeDefaultSequencingObject(Sample sample) { + Query query = entityManager.createNativeQuery("UPDATE sample SET default_sequencing_object = NULL where id = ?"); + query.setParameter(1, sample.getId()); + query.executeUpdate(); + } + + + @Transactional + public void removeDefaultGenomeAssembly(Sample sample) { + Query query = entityManager.createNativeQuery("UPDATE sample SET default_genome_assembly = NULL where id = ?"); + query.setParameter(1, sample.getId()); + query.executeUpdate(); + } } diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UISampleService.java b/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UISampleService.java index e185f2acee2..a1716a04f9a 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UISampleService.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/ria/web/services/UISampleService.java @@ -617,11 +617,6 @@ public String deleteSequencingObjectFromSample(Long sampleId, Long sequencingObj SequencingObject sequencingObject = sequencingObjectService.read(sequencingObjectId); try { - if (sample.getDefaultSequencingObject() != null - && sample.getDefaultSequencingObject().getId() == sequencingObjectId) { - sample.setDefaultSequencingObject(null); - sampleService.update(sample); - } sampleService.removeSequencingObjectFromSample(sample, sequencingObject); return messageSource.getMessage("server.SampleFiles.removeSequencingObjectSuccess", new Object[] {}, locale); @@ -644,11 +639,6 @@ public String deleteGenomeAssemblyFromSample(Long sampleId, Long genomeAssemblyI GenomeAssembly genomeAssembly = genomeAssemblyService.getGenomeAssemblyForSample(sample, genomeAssemblyId); try { - if (sample.getDefaultGenomeAssembly() != null - && sample.getDefaultGenomeAssembly().getId() == genomeAssemblyId) { - sample.setDefaultGenomeAssembly(null); - sampleService.update(sample); - } genomeAssemblyService.removeGenomeAssemblyFromSample(sample, genomeAssemblyId); return messageSource.getMessage("server.SampleFiles.removeGenomeAssemblySuccess", new Object[] {}, locale); } catch (Exception e) { diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/service/impl/GenomeAssemblyServiceImpl.java b/src/main/java/ca/corefacility/bioinformatics/irida/service/impl/GenomeAssemblyServiceImpl.java index f6a72de41f9..fd6c3106a52 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/service/impl/GenomeAssemblyServiceImpl.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/service/impl/GenomeAssemblyServiceImpl.java @@ -17,7 +17,9 @@ import ca.corefacility.bioinformatics.irida.model.sample.Sample; import ca.corefacility.bioinformatics.irida.repositories.assembly.GenomeAssemblyRepository; import ca.corefacility.bioinformatics.irida.repositories.joins.sample.SampleGenomeAssemblyJoinRepository; +import ca.corefacility.bioinformatics.irida.repositories.sample.SampleRepository; import ca.corefacility.bioinformatics.irida.service.GenomeAssemblyService; +import ca.corefacility.bioinformatics.irida.service.sample.SampleService; /** * Service implementation for storing and retrieving {@link GenomeAssembly} @@ -27,11 +29,18 @@ public class GenomeAssemblyServiceImpl extends CRUDServiceImpl> getSampleIdsBySampleNameForProjects(List pr public void removeSequencingObjectFromSample(Sample sample, SequencingObject object) { SampleSequencingObjectJoin readObjectForSample = ssoRepository.readObjectForSample(sample, object.getId()); ssoRepository.delete(readObjectForSample); + if (sample.getDefaultSequencingObject() != null + && sample.getDefaultSequencingObject().getId().equals(object.getId())) { + sampleRepository.removeDefaultSequencingObject(sample); + } } /** diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/service/remote/ProjectSynchronizationService.java b/src/main/java/ca/corefacility/bioinformatics/irida/service/remote/ProjectSynchronizationService.java index 46a09a27bca..8112f7e9a45 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/service/remote/ProjectSynchronizationService.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/service/remote/ProjectSynchronizationService.java @@ -186,7 +186,7 @@ public synchronized void findMarkedProjectsToSync() { * * @param project the {@link Project} to synchronize. This should have been read from a remote api. */ - private void syncProject(Project project) { + private void syncProject(Project project) throws Exception { SyncStatus syncType = project.getRemoteStatus().getSyncStatus(); project.getRemoteStatus().setSyncStatus(SyncStatus.UPDATING); @@ -305,7 +305,7 @@ private void syncProject(Project project) { * @return A list of {@link ProjectSynchronizationException}s, empty if no errors. */ public List syncSample(Sample sample, Project project, - Map existingSamples) { + Map existingSamples) throws Exception { Sample localSample; if (existingSamples.containsKey(sample.getRemoteStatus().getURL())) { diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/service/sample/SampleService.java b/src/main/java/ca/corefacility/bioinformatics/irida/service/sample/SampleService.java index 50289abd602..506da179e5d 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/service/sample/SampleService.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/service/sample/SampleService.java @@ -181,7 +181,7 @@ public Page getSamplesForProjectWithName(Project project, Str * @param sample {@link Sample} to remove sequences from * @param object {@link SequencingObject} to remove */ - public void removeSequencingObjectFromSample(Sample sample, SequencingObject object); + public void removeSequencingObjectFromSample(Sample sample, SequencingObject object) throws Exception; /** * Merge multiple samples into one. Merging samples copies the {@link SequenceFile} references from the set of diff --git a/src/main/java/ca/corefacility/bioinformatics/irida/web/controller/api/samples/RESTSampleSequenceFilesController.java b/src/main/java/ca/corefacility/bioinformatics/irida/web/controller/api/samples/RESTSampleSequenceFilesController.java index e10b7f19096..e33732cfcaa 100644 --- a/src/main/java/ca/corefacility/bioinformatics/irida/web/controller/api/samples/RESTSampleSequenceFilesController.java +++ b/src/main/java/ca/corefacility/bioinformatics/irida/web/controller/api/samples/RESTSampleSequenceFilesController.java @@ -695,7 +695,7 @@ public ResponseResource addNewSequenceFilePairToSample(@PathVa description = "Delete the sequencing object from a given sample.", tags = "samples") @RequestMapping(value = "/api/samples/{sampleId}/{objectType}/{objectId}", method = RequestMethod.DELETE) public ResponseResource removeSequenceFileFromSample(@PathVariable Long sampleId, - @PathVariable String objectType, @PathVariable Long objectId) { + @PathVariable String objectType, @PathVariable Long objectId) throws Exception { // load the project, sample and sequence file from the database Sample s = sampleService.read(sampleId); SequencingObject seqObject = sequencingObjectService.readSequencingObjectForSample(s, objectId); diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectHashingServiceIT.java b/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectHashingServiceIT.java index 46df5ed68fc..9114725bd9e 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectHashingServiceIT.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectHashingServiceIT.java @@ -103,7 +103,7 @@ public void hashChangesWithRemovedSample() { @WithMockUser(username = "admin", roles = "ADMIN") @Test - public void hashChangesWithRemovedSequencingObject() { + public void hashChangesWithRemovedSequencingObject() throws Exception { Project project = projectService.read(2L); Integer originalHash = hashingService.getProjectHash(project); diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectSynchronizationServiceTest.java b/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectSynchronizationServiceTest.java index 9377e7f5f3c..e174fe70c88 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectSynchronizationServiceTest.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/service/ProjectSynchronizationServiceTest.java @@ -199,7 +199,7 @@ public void testSyncProjectsUnauthorized() { } @Test - public void testSyncNewSample() { + public void testSyncNewSample() throws Exception { Sample sample = new Sample(); RemoteStatus sampleStatus = new RemoteStatus("http://sample", api); sample.setRemoteStatus(sampleStatus); @@ -215,7 +215,7 @@ public void testSyncNewSample() { } @Test - public void testExistingSample() { + public void testExistingSample() throws Exception { Sample sample = new Sample(); RemoteStatus sampleStatus = new RemoteStatus("http://sample", api); sample.setRemoteStatus(sampleStatus); @@ -233,7 +233,7 @@ public void testExistingSample() { } @Test - public void testSyncSampleNoAssemblies() { + public void testSyncSampleNoAssemblies() throws Exception { Sample sample = new Sample(); RemoteStatus sampleStatus = new RemoteStatus("http://sample", api); sample.setRemoteStatus(sampleStatus); @@ -253,7 +253,7 @@ public void testSyncSampleNoAssemblies() { } @Test - public void testSyncExistingSampleWithDeletedFiles() { + public void testSyncExistingSampleWithDeletedFiles() throws Exception { Sample sample = new Sample(); RemoteStatus sampleStatus = new RemoteStatus("http://sample", api); sample.setRemoteStatus(sampleStatus); @@ -278,7 +278,7 @@ public void testSyncExistingSampleWithDeletedFiles() { } @Test - public void testSyncExistingSampleWithDeletedAssemblies() { + public void testSyncExistingSampleWithDeletedAssemblies() throws Exception { Sample sample = new Sample(); RemoteStatus sampleStatus = new RemoteStatus("http://sample", api); sample.setRemoteStatus(sampleStatus); @@ -321,7 +321,7 @@ public void testSyncFiles() { } @Test - public void testSyncSampleNoFast5() { + public void testSyncSampleNoFast5() throws Exception { Sample sample = new Sample(); RemoteStatus sampleStatus = new RemoteStatus("http://sample", api); sample.setRemoteStatus(sampleStatus); diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/integration/sample/SampleServiceImplIT.java b/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/integration/sample/SampleServiceImplIT.java index 6c349e39a78..ee954b0db27 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/integration/sample/SampleServiceImplIT.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/integration/sample/SampleServiceImplIT.java @@ -18,6 +18,7 @@ import ca.corefacility.bioinformatics.irida.annotation.ServiceIntegrationTest; import ca.corefacility.bioinformatics.irida.exceptions.EntityNotFoundException; import ca.corefacility.bioinformatics.irida.exceptions.SequenceFileAnalysisException; +import ca.corefacility.bioinformatics.irida.model.assembly.GenomeAssembly; import ca.corefacility.bioinformatics.irida.model.joins.impl.ProjectSampleJoin; import ca.corefacility.bioinformatics.irida.model.project.Project; import ca.corefacility.bioinformatics.irida.model.project.ReferenceFile; @@ -26,9 +27,11 @@ import ca.corefacility.bioinformatics.irida.model.sample.Sample; import ca.corefacility.bioinformatics.irida.model.sample.metadata.MetadataEntry; import ca.corefacility.bioinformatics.irida.model.sample.metadata.ProjectMetadataResponse; +import ca.corefacility.bioinformatics.irida.model.sequenceFile.SequencingObject; import ca.corefacility.bioinformatics.irida.model.workflow.submission.AnalysisSubmission; import ca.corefacility.bioinformatics.irida.repositories.joins.sample.SampleGenomeAssemblyJoinRepository; import ca.corefacility.bioinformatics.irida.service.AnalysisSubmissionService; +import ca.corefacility.bioinformatics.irida.service.GenomeAssemblyService; import ca.corefacility.bioinformatics.irida.service.ProjectService; import ca.corefacility.bioinformatics.irida.service.SequencingObjectService; import ca.corefacility.bioinformatics.irida.service.sample.MetadataTemplateService; @@ -63,6 +66,9 @@ public class SampleServiceImplIT { @Autowired private MetadataTemplateService metadataTemplateService; + @Autowired + private GenomeAssemblyService genomeAssemblyService; + /** * Variation in a floating point number to be considered equal. */ @@ -80,6 +86,37 @@ public void testCreateSample() { assertEquals(sampleName, saved.getSampleName(), "Wrong name was saved."); } + @Test + @WithMockUser(username = "fbristow", roles = "ADMIN") + public void removeSampleDefaultSequencingObject() throws Exception { + Sample sample = sampleService.read(9L); + SequencingObject sequencingObject = objectService.read(2L); + sample.setDefaultSequencingObject(sequencingObject); + sampleService.update(sample); + + assertNotNull(sample.getDefaultSequencingObject()); + sampleService.removeSequencingObjectFromSample(sample, sequencingObject); + + Sample sampleAfterDelete = sampleService.read(9L); + assertNull(sampleAfterDelete.getDefaultSequencingObject()); + } + + @Test + @WithMockUser(username = "fbristow", roles = "ADMIN") + public void removeSampleDefaultGenomeAssembly() { + Sample sample = sampleService.read(2L); + GenomeAssembly genomeAssembly = sampleGenomeAssemblyJoinRepository.findBySampleAndAssemblyId(sample.getId(), 2L) + .getObject(); + sample.setDefaultGenomeAssembly(genomeAssembly); + sampleService.update(sample); + + assertNotNull(sample.getDefaultGenomeAssembly()); + genomeAssemblyService.removeGenomeAssemblyFromSample(sample, genomeAssembly.getId()); + + Sample sampleAfterDelete = sampleService.read(2L); + assertNull(sampleAfterDelete.getDefaultGenomeAssembly()); + } + /** * Straightforward merging of samples all belonging to the same project. */ diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/unit/sample/SampleServiceImplTest.java b/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/unit/sample/SampleServiceImplTest.java index dcd2408f158..9e53dfbefa4 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/unit/sample/SampleServiceImplTest.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/service/impl/unit/sample/SampleServiceImplTest.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Paths; import java.util.*; import org.junit.jupiter.api.BeforeEach; @@ -10,8 +11,10 @@ import ca.corefacility.bioinformatics.irida.exceptions.AnalysisAlreadySetException; import ca.corefacility.bioinformatics.irida.exceptions.SequenceFileAnalysisException; +import ca.corefacility.bioinformatics.irida.model.assembly.UploadedAssembly; import ca.corefacility.bioinformatics.irida.model.joins.Join; import ca.corefacility.bioinformatics.irida.model.joins.impl.ProjectSampleJoin; +import ca.corefacility.bioinformatics.irida.model.joins.impl.SampleGenomeAssemblyJoin; import ca.corefacility.bioinformatics.irida.model.project.Project; import ca.corefacility.bioinformatics.irida.model.sample.MetadataTemplateField; import ca.corefacility.bioinformatics.irida.model.sample.Sample; @@ -25,6 +28,7 @@ import ca.corefacility.bioinformatics.irida.model.workflow.analysis.AnalysisFastQC; import ca.corefacility.bioinformatics.irida.model.workflow.submission.AnalysisSubmission; import ca.corefacility.bioinformatics.irida.repositories.analysis.AnalysisRepository; +import ca.corefacility.bioinformatics.irida.repositories.assembly.GenomeAssemblyRepository; import ca.corefacility.bioinformatics.irida.repositories.joins.project.ProjectSampleJoinRepository; import ca.corefacility.bioinformatics.irida.repositories.joins.sample.SampleGenomeAssemblyJoinRepository; import ca.corefacility.bioinformatics.irida.repositories.joins.sample.SampleSequencingObjectJoinRepository; @@ -33,6 +37,8 @@ import ca.corefacility.bioinformatics.irida.repositories.sample.SampleRepository; import ca.corefacility.bioinformatics.irida.repositories.sequencefile.SequencingObjectRepository; import ca.corefacility.bioinformatics.irida.repositories.user.UserRepository; +import ca.corefacility.bioinformatics.irida.service.GenomeAssemblyService; +import ca.corefacility.bioinformatics.irida.service.impl.GenomeAssemblyServiceImpl; import ca.corefacility.bioinformatics.irida.service.impl.sample.SampleServiceImpl; import ca.corefacility.bioinformatics.irida.service.sample.SampleService; @@ -42,6 +48,8 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; +import javax.validation.Validator; + /** * Unit tests for {@link SampleServiceImpl}. */ @@ -58,6 +66,11 @@ public class SampleServiceImplTest { private UserRepository userRepository; private MetadataEntryRepository metadataEntryRepository; + private GenomeAssemblyRepository genomeAssemblyRepository; + private GenomeAssemblyService genomeAssemblyService; + + private Validator validator; + /** * Variation in a floating point number to be considered equal. */ @@ -77,6 +90,11 @@ public void setUp() { sampleService = new SampleServiceImpl(sampleRepository, psjRepository, analysisRepository, ssoRepository, qcEntryRepository, sequencingObjectRepository, sampleGenomeAssemblyJoinRepository, userRepository, metadataEntryRepository, null); + + genomeAssemblyRepository = mock(GenomeAssemblyRepository.class); + validator = mock(Validator.class); + genomeAssemblyService = new GenomeAssemblyServiceImpl(genomeAssemblyRepository, + sampleGenomeAssemblyJoinRepository, null, sampleService, sampleRepository); } @Test @@ -97,20 +115,46 @@ public void testGetSampleForProject() { } @Test - public void testRemoveSequenceFileFromSample() { + public void testRemoveSequencingObjectFromSample() throws Exception { Sample s = new Sample(); s.setId(1111L); SequenceFile sf = new SequenceFile(); sf.setId(2222L); SingleEndSequenceFile obj = new SingleEndSequenceFile(sf); obj.setId(2L); + s.setDefaultSequencingObject(obj); SampleSequencingObjectJoin join = new SampleSequencingObjectJoin(s, obj); when(ssoRepository.readObjectForSample(s, obj.getId())).thenReturn(join); + assertNotNull(s.getDefaultSequencingObject()); + assertEquals(s.getDefaultSequencingObject().getId(), 2L, + "The default sequencing object id should match the sequencing object id"); sampleService.removeSequencingObjectFromSample(s, obj); verify(ssoRepository).delete(join); + verify(sampleRepository).removeDefaultSequencingObject(s); + } + + @Test + public void testRemoveGenomeAssemblyFromSample() { + Sample s = new Sample(); + s.setId(1111L); + UploadedAssembly uploadedAssembly = new UploadedAssembly(Paths.get("/path/to/file")); + uploadedAssembly.setId(2L); + s.setDefaultGenomeAssembly(uploadedAssembly); + SampleGenomeAssemblyJoin join = new SampleGenomeAssemblyJoin(s, uploadedAssembly); + + when(sampleGenomeAssemblyJoinRepository.findBySampleAndAssemblyId(s.getId(), + uploadedAssembly.getId())).thenReturn(join); + assertNotNull(s.getDefaultGenomeAssembly()); + assertEquals(s.getDefaultGenomeAssembly().getId(), 2L, + "The default genome assembly should match the genome assembly id"); + + genomeAssemblyService.removeGenomeAssemblyFromSample(s, uploadedAssembly.getId()); + + verify(sampleGenomeAssemblyJoinRepository).delete(join); + verify(sampleRepository).removeDefaultGenomeAssembly(s); } @Test diff --git a/src/test/java/ca/corefacility/bioinformatics/irida/web/controller/test/unit/samples/SampleSequenceFilesControllerTest.java b/src/test/java/ca/corefacility/bioinformatics/irida/web/controller/test/unit/samples/SampleSequenceFilesControllerTest.java index 64a2704e5c7..d77768c9cd8 100644 --- a/src/test/java/ca/corefacility/bioinformatics/irida/web/controller/test/unit/samples/SampleSequenceFilesControllerTest.java +++ b/src/test/java/ca/corefacility/bioinformatics/irida/web/controller/test/unit/samples/SampleSequenceFilesControllerTest.java @@ -130,7 +130,7 @@ public void testGetSampleSequenceFiles() throws IOException { } @Test - public void testRemoveSequenceFileFromSample() throws IOException { + public void testRemoveSequenceFileFromSample() throws Exception { Sample s = TestDataFactory.constructSample(); SingleEndSequenceFile so = TestDataFactory.constructSingleEndSequenceFile();