From 8d99502a9b5c99453efaf4753da5d0a048f6adfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jhoan=20Manuel=20Mu=C3=B1oz=20Serrano?= Date: Thu, 25 Jul 2024 16:52:38 +0100 Subject: [PATCH] Pivotal ID # 185361632: Avoid Files Modification On Public Studies (#855) https://www.pivotaltracker.com/story/show/185361632 - Create a new stage to validate file changes - Add new permission to allow file modifications on public studies - Mark the submission as invalid in case the file validation fails - Add integration tests --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- .../main/kotlin/ebi/ac/uk/ftp/FtpClient.kt | 2 + .../kotlin/ebi/ac/uk/ftp/FtpClientTest.kt | 10 +- .../ebi/ac/uk/io/sources/FileSourcesList.kt | 2 +- .../kotlin/ebi/ac/uk/model/RequestStatus.kt | 2 + .../ac/uk/extended/events/RequestCreated.kt | 7 +- .../extended/model/ExtFileExtensionsTest.kt | 4 +- .../uk/ebi/biostd/json/JsonSerializerTest.kt | 2 +- .../tsv/FileListTsvStreamDeserializerTest.kt | 2 +- .../uk/ebi/biostd/tsv/TsvDeserializerTest.kt | 38 +- .../TsvSingleElementDeserializationTest.kt | 10 +- .../test/kotlin/ebi/ac/uk/io/FileUtilsTest.kt | 2 +- .../events/service/EventsPublisherService.kt | 10 + .../persistence/common/model/AccessType.kt | 1 + .../common/model/SubmissionRequest.kt | 39 +- .../common/model/SubmissionRequestFile.kt | 2 + .../shared/ConverterCommonsFields.kt | 2 + .../doc/model/SubmissionRequestModel.kt | 4 + ...ubmissionRequestMongoPersistenceService.kt | 6 + .../SubmissionRequestDocDataRepositoryTest.kt | 8 + .../service/ExtSubmissionRepositoryTest.kt | 8 +- .../doc/service/StatsMongoDataServiceTest.kt | 4 +- .../SubmissionMongoQueryServiceTest.kt | 2 + ...ssionRequestMongoPersistenceServiceTest.kt | 4 + .../common/properties/TaskProperties.kt | 3 +- .../submission/config/SubmitterConfig.kt | 23 +- .../request/SubmissionRequestCleanIndexer.kt | 76 ++- .../request/SubmissionRequestCleaner.kt | 24 +- .../request/SubmissionRequestValidator.kt | 61 ++ .../submitter/ExtSubmissionSubmitter.kt | 6 + .../submitter/ExtendedSubmissionSubmitter.kt | 6 +- .../submitter/LocalExtSubmissionSubmitter.kt | 27 +- .../submitter/RemoteExtSubmissionSubmitter.kt | 7 + .../exceptions/InvalidPermissionsException.kt | 5 - .../LocalExtSubmissionSubmitterTest.kt | 335 ---------- .../SubmissionRequestCleanIndexerTest.kt | 256 -------- .../request/SubmissionRequestCleanerTest.kt | 116 ---- .../request/SubmissionRequestIndexerTest.kt | 79 --- .../request/SubmissionRequestLoaderTest.kt | 112 ---- .../request/SubmissionRequestProcessorTest.kt | 90 --- .../request/SubmissionRequestReleaserTest.kt | 273 -------- .../request/SubmissionRequestSaverTest.kt | 102 --- .../exception/CustomErrorHandlerTest.kt | 2 +- .../components/IUserPrivilegesService.kt | 5 + .../security/service/UserPrivilegesService.kt | 8 + .../uk/security/service/ProfileServiceTest.kt | 2 +- .../ac/ebi/biostd/submission/SubmissionApp.kt | 2 + .../itest/test/files/UserFileApiTest.kt | 3 +- .../submission/query/SubmissionListApiTest.kt | 12 +- .../submit/MultipartFileSubmissionApiTest.kt | 1 - .../submission/submit/ResubmissionApiTest.kt | 621 +++++++++++------- .../itestsInventory/itestsInventory.md | 10 +- .../common/config/SubmissionWebConfig.kt | 7 +- .../files/service/ftp/FtpFileService.kt | 2 +- .../service/SubmissionMessageListener.kt | 12 +- .../biostd/resolvers/TestUserPathResolver.kt | 21 - .../stats/web/mapping/StatsMapperTest.kt | 4 +- 57 files changed, 738 insertions(+), 1748 deletions(-) create mode 100644 submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestValidator.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/extended/LocalExtSubmissionSubmitterTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexerTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanerTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestIndexerTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestLoaderTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestProcessorTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestReleaserTest.kt delete mode 100644 submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestSaverTest.kt delete mode 100644 submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/resolvers/TestUserPathResolver.kt diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 86ab765ad..0c8af2487 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -79,7 +79,7 @@ object Versions { const val CommonsFileUploadVersion = "1.4" const val CommonsLang3Version = "3.8.1" const val CommonsIOVersion = "2.6" - const val CommonsNetVersion = "3.6" + const val CommonsNetVersion = "3.11.1" const val CommonsPoolVersion = "2.12.0" const val CommonsCsvVersion = "1.8" const val MySqlVersion = "8.3.0" diff --git a/client/ftp-webclient/src/main/kotlin/ebi/ac/uk/ftp/FtpClient.kt b/client/ftp-webclient/src/main/kotlin/ebi/ac/uk/ftp/FtpClient.kt index 7a84980f6..4419df9c9 100644 --- a/client/ftp-webclient/src/main/kotlin/ebi/ac/uk/ftp/FtpClient.kt +++ b/client/ftp-webclient/src/main/kotlin/ebi/ac/uk/ftp/FtpClient.kt @@ -1,5 +1,6 @@ package ebi.ac.uk.ftp +import org.apache.commons.net.ftp.FTP import org.apache.commons.net.ftp.FTPClient import org.apache.commons.net.ftp.FTPFile import java.io.InputStream @@ -72,6 +73,7 @@ private class SimpleFtpClient( ftpClientPool.execute { ftp -> for ((path, inputStream) in files) { ftp.createFtpFolder(path.parent) + ftp.setFileType(FTP.BINARY_FILE_TYPE) inputStream().use { ftp.storeFile(path.toString(), it) } } } diff --git a/client/ftp-webclient/src/test/kotlin/ebi/ac/uk/ftp/FtpClientTest.kt b/client/ftp-webclient/src/test/kotlin/ebi/ac/uk/ftp/FtpClientTest.kt index b6909907f..55d0a35af 100644 --- a/client/ftp-webclient/src/test/kotlin/ebi/ac/uk/ftp/FtpClientTest.kt +++ b/client/ftp-webclient/src/test/kotlin/ebi/ac/uk/ftp/FtpClientTest.kt @@ -26,10 +26,10 @@ class FtpClientTest { testInstance.uploadFile(rootPath.resolve("a-folder").resolve("file1.txt")) { tempFile.inputStream() } val files = testInstance.listFiles(rootPath) - assertThat(files).hasOnlyOneElementSatisfying { it.name == "a-folder" && it.isDirectory } + assertThat(files).satisfiesOnlyOnce { it.name == "a-folder" && it.isDirectory } // .hasOnlyOneElementSatisfying { } val folderFiles = testInstance.listFiles(rootPath.resolve("a-folder")) - assertThat(folderFiles).hasOnlyOneElementSatisfying { it.name == "file1.txt" && it.isFile } + assertThat(folderFiles).satisfiesOnlyOnce { it.name == "file1.txt" && it.isFile } } @RetryingTest(TEST_RETRY) @@ -71,9 +71,9 @@ class FtpClientTest { val file = files.first() assertThat(file.name).isEqualTo("test-file.txt") - val outputFile = createTempFile() + val outputFile = createTempFile("") outputFile.outputStream().use { testInstance.downloadFile(filePath, it) } - assertThat(outputFile).hasSameContentAs(tempFile) + assertThat(outputFile).hasSameBinaryContentAs(tempFile) } companion object { @@ -87,7 +87,7 @@ class FtpClientTest { ) } - val HOME = Paths.get("") + private val HOME = Paths.get("") const val FTP_USER = "ftpUser" const val FTP_PASSWORD = "ftpPassword" const val FTP_ROOT_PATH = ".test" diff --git a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/io/sources/FileSourcesList.kt b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/io/sources/FileSourcesList.kt index 686c97577..a70b0c36f 100644 --- a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/io/sources/FileSourcesList.kt +++ b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/io/sources/FileSourcesList.kt @@ -35,7 +35,7 @@ private val validPathPattern = append("\$") // End of the line }.trimIndent().toRegex() -class FileSourcesList(val checkFilesPath: Boolean, val sources: List) { +class FileSourcesList(private val checkFilesPath: Boolean, val sources: List) { suspend fun findExtFile( path: String, type: String, diff --git a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/RequestStatus.kt b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/RequestStatus.kt index 722405566..a55ec4f5c 100644 --- a/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/RequestStatus.kt +++ b/commons/commons-bio/src/main/kotlin/ebi/ac/uk/model/RequestStatus.kt @@ -4,12 +4,14 @@ enum class RequestStatus { REQUESTED, INDEXED, LOADED, + VALIDATED, INDEXED_CLEANED, CLEANED, FILES_COPIED, CHECK_RELEASED, PERSISTED, PROCESSED, + INVALID, ; companion object { diff --git a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/events/RequestCreated.kt b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/events/RequestCreated.kt index 7ce6dee07..78c89efeb 100644 --- a/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/events/RequestCreated.kt +++ b/commons/commons-model-extended/src/main/kotlin/ebi/ac/uk/extended/events/RequestCreated.kt @@ -17,12 +17,17 @@ data class RequestIndexed( @JsonProperty("version") override val version: Int, ) : RequestMessage +data class RequestLoaded( + @JsonProperty("accNo") override val accNo: String, + @JsonProperty("version") override val version: Int, +) : RequestMessage + data class RequestToCleanIndexed( @JsonProperty("accNo") override val accNo: String, @JsonProperty("version") override val version: Int, ) : RequestMessage -data class RequestLoaded( +data class RequestValidated( @JsonProperty("accNo") override val accNo: String, @JsonProperty("version") override val version: Int, ) : RequestMessage diff --git a/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/model/ExtFileExtensionsTest.kt b/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/model/ExtFileExtensionsTest.kt index 96c6b1988..9e1c1a7df 100644 --- a/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/model/ExtFileExtensionsTest.kt +++ b/commons/commons-model-extended/src/test/kotlin/ebi/ac/uk/extended/model/ExtFileExtensionsTest.kt @@ -27,7 +27,7 @@ class ExtFileExtensionsTest { val newAttributes = listOf(ExtAttribute("Override", "New")) val copied = fireFile.copyWithAttributes(newAttributes) - assertThat(copied).isEqualToIgnoringGivenFields(fireFile, "attributes") + assertThat(copied).usingRecursiveComparison().ignoringFields("attributes").isEqualTo(fireFile) assertThat(copied.attributes).isEqualTo(newAttributes) } @@ -49,7 +49,7 @@ class ExtFileExtensionsTest { val newAttributes = listOf(ExtAttribute("Override", "New")) val copied = nfsFile.copyWithAttributes(newAttributes) - assertThat(copied).isEqualToIgnoringGivenFields(nfsFile, "attributes") + assertThat(copied).usingRecursiveComparison().ignoringFields("attributes").isEqualTo(nfsFile) assertThat(copied.attributes).isEqualTo(newAttributes) } } diff --git a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/json/JsonSerializerTest.kt b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/json/JsonSerializerTest.kt index a35692121..73485c486 100644 --- a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/json/JsonSerializerTest.kt +++ b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/json/JsonSerializerTest.kt @@ -39,7 +39,7 @@ class JsonSerializerTest( fileSystem.outputStream().use { jsonSerializer.serializeFileList(files.asSequence(), it) } val response = fileSystem.inputStream().use { jsonSerializer.deserializeFileList(it).toList() } - assertThat(response).allSatisfy { assertThat(it).isEqualToComparingFieldByField(iterator.next()) } + assertThat(response).allSatisfy { assertThat(it).usingRecursiveComparison().isEqualTo(iterator.next()) } assertThat(response).hasSize(20_000) } diff --git a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/FileListTsvStreamDeserializerTest.kt b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/FileListTsvStreamDeserializerTest.kt index 57a3f1d8b..3d6e30b8e 100644 --- a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/FileListTsvStreamDeserializerTest.kt +++ b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/FileListTsvStreamDeserializerTest.kt @@ -97,7 +97,7 @@ class FileListTsvStreamDeserializerTest( output.outputStream().use { testInstance.serializeFileList(files.asFlow(), it) } val result = output.inputStream().use { testInstance.deserializeFileList(it).toList() } - assertThat(result).allSatisfy { assertThat(it).isEqualToComparingFieldByField(iterator.next()) } + assertThat(result).allSatisfy { assertThat(it).usingRecursiveComparison().isEqualTo(iterator.next()) } assertThat(result).hasSize(20000) } diff --git a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvDeserializerTest.kt b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvDeserializerTest.kt index 3e6c2ca78..44377060f 100644 --- a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvDeserializerTest.kt +++ b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvDeserializerTest.kt @@ -55,7 +55,7 @@ class TsvDeserializerTest { fun `basic submission`() { val result = deserializer.deserialize(basicSubmission().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "Basic Submission") attribute("DataSource", "EuropePMC") @@ -68,7 +68,7 @@ class TsvDeserializerTest { fun `submission with empty attribute`() { val result = deserializer.deserialize(submissionWithEmptyAttribute().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "Basic Submission") attribute("DataSource", "EuropePMC") @@ -81,7 +81,7 @@ class TsvDeserializerTest { fun `submission with blank attribute`() { val result = deserializer.deserialize(submissionWithBlankAttribute().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "Basic Submission") attribute("DataSource", "EuropePMC") @@ -94,7 +94,7 @@ class TsvDeserializerTest { fun `submission with null attribute`() { val result = deserializer.deserialize(submissionWithNullAttribute().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "Basic Submission") attribute("DataSource", "EuropePMC") @@ -107,7 +107,7 @@ class TsvDeserializerTest { fun `submission with quoted value`() { val result = deserializer.deserialize(submissionWithQuoteValue().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "The \"Submission\": title.") attribute("Abstract", "\"The Submission\": this is description.") @@ -121,7 +121,7 @@ class TsvDeserializerTest { fun `basic submission with comments`() { val result = deserializer.deserialize(basicSubmissionWithComments().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "Basic Submission") attribute("DataSource", "EuropePMC") @@ -134,7 +134,7 @@ class TsvDeserializerTest { fun `submission with multiline attribute value`() { val result = deserializer.deserialize(basicSubmissionWithMultiline().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC123") { attribute("Title", "This is a really long title \n with a break line") attribute("Another", "another attribute") @@ -146,7 +146,7 @@ class TsvDeserializerTest { fun `detailed attributes`() { val result = deserializer.deserialize(submissionWithDetailedAttributes().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC124") { attribute("Title", "Submission With Detailed Attributes") @@ -167,7 +167,7 @@ class TsvDeserializerTest { fun `submission with root section`() { val result = deserializer.deserialize(submissionWithRootSection().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -183,7 +183,7 @@ class TsvDeserializerTest { fun `submission with generic root section`() { val result = deserializer.deserialize(submissionWithGenericRootSection().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") section("Compound") { @@ -197,7 +197,7 @@ class TsvDeserializerTest { fun `submission with multiple line breaks`() { val result = deserializer.deserialize(submissionWithMultipleLineBreaks().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -213,7 +213,7 @@ class TsvDeserializerTest { fun subsection() { val result = deserializer.deserialize(submissionWithSubsection().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -235,7 +235,7 @@ class TsvDeserializerTest { fun `inner subsections`() { val result = deserializer.deserialize(submissionWithInnerSubsections().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -278,7 +278,7 @@ class TsvDeserializerTest { fun `inner subsections table`() { val result = deserializer.deserialize(submissionWithInnerSubsectionsTable().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -321,7 +321,7 @@ class TsvDeserializerTest { fun links() { val result = deserializer.deserialize(submissionWithLinks().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -340,7 +340,7 @@ class TsvDeserializerTest { fun `links table with attribute details`() { val result = deserializer.deserialize(submissionWithLinksTable().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -376,7 +376,7 @@ class TsvDeserializerTest { fun files() { val result = deserializer.deserialize(submissionWithFiles().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -396,7 +396,7 @@ class TsvDeserializerTest { fun `files table`() { val result = deserializer.deserialize(submissionWithFilesTable().toString()) - assertThat(result).isEqualToComparingFieldByField( + assertThat(result).usingRecursiveComparison().isEqualTo( submission("S-EPMC125") { attribute("Title", "Test Submission") @@ -526,7 +526,7 @@ class TsvDeserializerTest { assertEither(sections.first()).hasRightValueSatisfying { val innerSections = it.elements assertThat(innerSections).hasSize(1) - assertThat(innerSections.first()).isEqualToComparingFieldByField( + assertThat(innerSections.first()).usingRecursiveComparison().isEqualTo( Section( type = "Data", accNo = "DT-1", diff --git a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvSingleElementDeserializationTest.kt b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvSingleElementDeserializationTest.kt index 96303e4fa..55a26df29 100644 --- a/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvSingleElementDeserializationTest.kt +++ b/commons/commons-serialization/src/test/kotlin/ac/uk/ebi/biostd/tsv/TsvSingleElementDeserializationTest.kt @@ -27,7 +27,7 @@ class TsvSingleElementDeserializationTest { line() }.toString() - assertThat(deserializer.deserializeElement(tsv)).isEqualToComparingFieldByField( + assertThat(deserializer.deserializeElement(tsv)).usingRecursiveComparison().isEqualTo( file("File1.txt") { attribute("Attr", "Value") }, @@ -43,7 +43,7 @@ class TsvSingleElementDeserializationTest { line() }.toString() - assertThat(deserializer.deserializeElement(tsv)).isEqualToComparingFieldByField( + assertThat(deserializer.deserializeElement(tsv)).usingRecursiveComparison().isEqualTo( filesTable { file("File1.txt") { attribute("Attr", "Value") @@ -61,7 +61,7 @@ class TsvSingleElementDeserializationTest { line() }.toString() - assertThat(deserializer.deserializeElement(tsv)).isEqualToComparingFieldByField( + assertThat(deserializer.deserializeElement(tsv)).usingRecursiveComparison().isEqualTo( link("http://alink.org") { attribute("Attr", "Value") }, @@ -77,7 +77,7 @@ class TsvSingleElementDeserializationTest { line() }.toString() - assertThat(deserializer.deserializeElement(tsv)).isEqualToComparingFieldByField( + assertThat(deserializer.deserializeElement(tsv)).usingRecursiveComparison().isEqualTo( linksTable { link("http://alink.org") { attribute("Attr", "Value") @@ -98,7 +98,7 @@ class TsvSingleElementDeserializationTest { line() }.toString() - assertThat(deserializer.deserializeElement(tsv)).isEqualToComparingFieldByField( + assertThat(deserializer.deserializeElement(tsv)).usingRecursiveComparison().isEqualTo( linksTable { link("AF069307") { attribute("Attr1", "Value 1") diff --git a/commons/commons-util/src/test/kotlin/ebi/ac/uk/io/FileUtilsTest.kt b/commons/commons-util/src/test/kotlin/ebi/ac/uk/io/FileUtilsTest.kt index 24f542fe4..bc88ba52e 100644 --- a/commons/commons-util/src/test/kotlin/ebi/ac/uk/io/FileUtilsTest.kt +++ b/commons/commons-util/src/test/kotlin/ebi/ac/uk/io/FileUtilsTest.kt @@ -118,7 +118,7 @@ internal class FileUtilsTest(private val temporaryFolder: TemporaryFolder) { assertThat(target).isDirectory() assertThat(nestedDir).isDirectory() - assertThat(nestedFile).hasSameContentAs(subDirFile) + assertThat(nestedFile).hasSameTextualContentAs(subDirFile) assertThat(getPosixFilePermissions(target.toPath())).containsExactlyInAnyOrderElementsOf(RWX______) assertThat(getPosixFilePermissions(nestedDir.toPath())).containsExactlyInAnyOrderElementsOf(RWX______) assertThat(getPosixFilePermissions(nestedFile.toPath())).containsExactlyInAnyOrderElementsOf(RW_______) diff --git a/events/events-publisher/src/main/kotlin/uk/ac/ebi/events/service/EventsPublisherService.kt b/events/events-publisher/src/main/kotlin/uk/ac/ebi/events/service/EventsPublisherService.kt index fcafe4210..0ff546eb2 100644 --- a/events/events-publisher/src/main/kotlin/uk/ac/ebi/events/service/EventsPublisherService.kt +++ b/events/events-publisher/src/main/kotlin/uk/ac/ebi/events/service/EventsPublisherService.kt @@ -16,6 +16,7 @@ import ebi.ac.uk.extended.events.RequestLoaded import ebi.ac.uk.extended.events.RequestMessage import ebi.ac.uk.extended.events.RequestPersisted import ebi.ac.uk.extended.events.RequestToCleanIndexed +import ebi.ac.uk.extended.events.RequestValidated import ebi.ac.uk.extended.events.SecurityNotification import ebi.ac.uk.extended.events.SubmissionMessage import org.springframework.amqp.rabbit.core.RabbitTemplate @@ -77,6 +78,15 @@ class EventsPublisherService( RequestToCleanIndexed(accNo, version), ) + fun requestValidated( + accNo: String, + version: Int, + ) = rabbitTemplate.convertAndSend( + BIOSTUDIES_EXCHANGE, + notificationsProperties.requestRoutingKey, + RequestValidated(accNo, version), + ) + fun requestCleaned( accNo: String, version: Int, diff --git a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/AccessType.kt b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/AccessType.kt index d3df11e7a..903e98cc0 100644 --- a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/AccessType.kt +++ b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/AccessType.kt @@ -5,6 +5,7 @@ enum class AccessType { ATTACH, UPDATE, DELETE, + UPDATE_PUBLIC, ADMIN, } diff --git a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequest.kt b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequest.kt index 5e3d38da2..1b7b79bd7 100644 --- a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequest.kt +++ b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequest.kt @@ -12,7 +12,9 @@ data class SubmissionRequest( val status: RequestStatus, val totalFiles: Int, val conflictingFiles: Int, + val conflictingPageTab: Int, val deprecatedFiles: Int, + val deprecatedPageTab: Int, val reusedFiles: Int, val currentIndex: Int, val modificationTime: OffsetDateTime, @@ -25,7 +27,9 @@ data class SubmissionRequest( status = REQUESTED, totalFiles = 0, conflictingFiles = 0, + conflictingPageTab = 0, deprecatedFiles = 0, + deprecatedPageTab = 0, reusedFiles = 0, currentIndex = 0, previousVersion = null, @@ -59,24 +63,30 @@ data class SubmissionRequest( * Create a Submission Request after clean indexing stage setting conflicted, deprecated files and previous version * fields. */ - fun cleanIndexed( - conflictingFiles: Int, - deprecatedFiles: Int, - reusedFiles: Int, - previousVersion: Int?, - ): SubmissionRequest { + fun cleanIndexed(fileChanges: SubmissionRequestFileChanges): SubmissionRequest { return copy( status = RequestStatus.INDEXED_CLEANED, modificationTime = OffsetDateTime.now(), currentIndex = 0, - conflictingFiles = conflictingFiles, - deprecatedFiles = deprecatedFiles, - reusedFiles = reusedFiles, - previousVersion = previousVersion, + conflictingFiles = fileChanges.conflictingFiles, + conflictingPageTab = fileChanges.conflictingPageTab, + deprecatedFiles = fileChanges.deprecatedFiles, + deprecatedPageTab = fileChanges.deprecatedPageTab, + reusedFiles = fileChanges.reusedFiles, + previousVersion = fileChanges.previousVersion, ) } } +data class SubmissionRequestFileChanges( + val reusedFiles: Int, + val deprecatedFiles: Int, + val deprecatedPageTab: Int, + val conflictingFiles: Int, + val conflictingPageTab: Int, + val previousVersion: Int?, +) + /** * Retrieves the expected action to be performed when submission request is the given status. */ @@ -86,10 +96,11 @@ val RequestStatus.action: String REQUESTED -> "Indexing" RequestStatus.INDEXED -> "Loading" RequestStatus.LOADED -> "Indexing Files to Clean" - RequestStatus.INDEXED_CLEANED -> "Cleaning" - RequestStatus.CLEANED -> "Copy Files" - RequestStatus.FILES_COPIED -> "Release Files" - RequestStatus.CHECK_RELEASED -> "Save Submission" + RequestStatus.INDEXED_CLEANED -> "Validating" + RequestStatus.VALIDATED -> "Cleaning" + RequestStatus.CLEANED -> "Copying Files" + RequestStatus.FILES_COPIED -> "Releasing Files" + RequestStatus.CHECK_RELEASED -> "Saving Submission" RequestStatus.PERSISTED -> "Submission Post Processing" else -> error("Invalid state $this") } diff --git a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequestFile.kt b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequestFile.kt index 11a4b0d53..9f153ddda 100644 --- a/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequestFile.kt +++ b/submission/persistence-common-api/src/main/kotlin/ac/uk/ebi/biostd/persistence/common/model/SubmissionRequestFile.kt @@ -31,6 +31,8 @@ enum class RequestFileStatus { RELEASED, UNRELEASED, CONFLICTING, + CONFLICTING_PAGE_TAB, DEPRECATED, + DEPRECATED_PAGE_TAB, REUSED, } diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt index 1200814d1..2a72179c2 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/db/converters/shared/ConverterCommonsFields.kt @@ -155,7 +155,9 @@ object DocRequestFields { const val RQT_SUBMISSION = "submission" const val RQT_TOTAL_FILES = "totalFiles" const val RQT_DEPRECATED_FILES = "deprecatedFiles" + const val RQT_DEPRECATED_PAGE_TAB = "deprecatedPageTab" const val RQT_CONFLICTING_FILES = "conflictingFiles" + const val RQT_CONFLICTING_PAGE_TAB = "conflictingPageTab" const val RQT_REUSED_FILES = "reusedFiles" const val RQT_IDX = "currentIndex" const val RQT_MODIFICATION_TIME = "modificationTime" diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt index 83288ba9b..c026a91e9 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/model/SubmissionRequestModel.kt @@ -22,7 +22,9 @@ data class DocSubmissionRequest( val submission: DBObject, val totalFiles: Int, val conflictingFiles: Int, + val conflictingPageTab: Int, val deprecatedFiles: Int, + val deprecatedPageTab: Int, val reusedFiles: Int, val currentIndex: Int, val previousVersion: Int?, @@ -40,7 +42,9 @@ data class DocSubmissionRequest( .setOnInsert(DocRequestFields.RQT_SUBMISSION, submission) .setOnInsert(DocRequestFields.RQT_TOTAL_FILES, totalFiles) .setOnInsert(DocRequestFields.RQT_DEPRECATED_FILES, deprecatedFiles) + .setOnInsert(DocRequestFields.RQT_DEPRECATED_PAGE_TAB, deprecatedPageTab) .setOnInsert(DocRequestFields.RQT_CONFLICTING_FILES, conflictingFiles) + .setOnInsert(DocRequestFields.RQT_CONFLICTING_PAGE_TAB, conflictingPageTab) .setOnInsert(DocRequestFields.RQT_REUSED_FILES, reusedFiles) .setOnInsert(DocRequestFields.RQT_PREV_SUB_VERSION, previousVersion) .setOnInsert(DocRequestFields.RQT_IDX, currentIndex) diff --git a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt index fc648d06f..96bee3769 100644 --- a/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt +++ b/submission/persistence-mongo/src/main/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceService.kt @@ -92,7 +92,9 @@ class SubmissionRequestMongoPersistenceService( notifyTo = request.notifyTo, status = request.status, conflictingFiles = request.conflictingFiles, + conflictingPageTab = request.conflictingPageTab, deprecatedFiles = request.deprecatedFiles, + deprecatedPageTab = request.deprecatedPageTab, reusedFiles = request.reusedFiles, totalFiles = request.totalFiles, currentIndex = request.currentIndex, @@ -156,7 +158,9 @@ class SubmissionRequestMongoPersistenceService( submission = BasicDBObject.parse(content), totalFiles = rqt.totalFiles, conflictingFiles = rqt.conflictingFiles, + conflictingPageTab = rqt.conflictingPageTab, deprecatedFiles = rqt.deprecatedFiles, + deprecatedPageTab = rqt.deprecatedPageTab, reusedFiles = rqt.reusedFiles, currentIndex = rqt.currentIndex, previousVersion = rqt.previousVersion, @@ -174,7 +178,9 @@ class SubmissionRequestMongoPersistenceService( status = request.status, totalFiles = request.totalFiles, conflictingFiles = request.conflictingFiles, + conflictingPageTab = request.deprecatedPageTab, deprecatedFiles = request.deprecatedFiles, + deprecatedPageTab = request.deprecatedPageTab, reusedFiles = request.reusedFiles, currentIndex = request.currentIndex, previousVersion = request.previousVersion, diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt index ea48a9f90..cb34fef0b 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/db/data/SubmissionRequestDocDataRepositoryTest.kt @@ -58,7 +58,9 @@ class SubmissionRequestDocDataRepositoryTest( submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0" }.toString()), totalFiles = 5, deprecatedFiles = 10, + deprecatedPageTab = 3, conflictingFiles = 12, + conflictingPageTab = 8, reusedFiles = 5, currentIndex = 6, modificationTime = Instant.now(), @@ -99,7 +101,9 @@ class SubmissionRequestDocDataRepositoryTest( submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0" }.toString()), totalFiles = 5, conflictingFiles = 1, + conflictingPageTab = 3, deprecatedFiles = 10, + deprecatedPageTab = 7, reusedFiles = 2, currentIndex = 6, modificationTime = Instant.now(), @@ -119,7 +123,9 @@ class SubmissionRequestDocDataRepositoryTest( submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0-b" }.toString()), totalFiles = 51, conflictingFiles = 1, + conflictingPageTab = 3, deprecatedFiles = 10, + deprecatedPageTab = 8, reusedFiles = 2, currentIndex = 61, modificationTime = Instant.now().plusSeconds(10), @@ -160,7 +166,9 @@ class SubmissionRequestDocDataRepositoryTest( submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0-b" }.toString()), totalFiles = 51, conflictingFiles = 1, + conflictingPageTab = 3, deprecatedFiles = 10, + deprecatedPageTab = 8, reusedFiles = 2, currentIndex = 61, modificationTime = Instant.now().plusSeconds(10), diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/ExtSubmissionRepositoryTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/ExtSubmissionRepositoryTest.kt index e5b8296b0..becce5019 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/ExtSubmissionRepositoryTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/ExtSubmissionRepositoryTest.kt @@ -74,10 +74,10 @@ class ExtSubmissionRepositoryTest( val result = testInstance.saveSubmission(submission) - assertThat(result.section).isEqualToIgnoringGivenFields( - section.copy(fileList = defaultFileList(filesUrl = null)), - "fileList", - ) + assertThat(result.section) + .usingRecursiveComparison() + .ignoringFields("fileList") + .isEqualTo(section.copy(fileList = defaultFileList(filesUrl = null))) val savedSubmission = subDataRepository.getSubmission(submission.accNo, 1) assertThat(subDataRepository.findAll().toList()).hasSize(1) diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/StatsMongoDataServiceTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/StatsMongoDataServiceTest.kt index cbba95783..bfc9be323 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/StatsMongoDataServiceTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/StatsMongoDataServiceTest.kt @@ -124,8 +124,8 @@ class StatsMongoDataServiceTest( val result = testInstance.saveAll(stats) assertThat(result).hasSize(2) - assertThat(result.first()).isEqualToComparingFieldByField(stats.third()) - assertThat(result.second()).isEqualToComparingFieldByField(stats.second()) + assertThat(result.first()).usingRecursiveComparison().isEqualTo(stats.third()) + assertThat(result.second()).usingRecursiveComparison().isEqualTo(stats.second()) } @Test diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionMongoQueryServiceTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionMongoQueryServiceTest.kt index 09f64570b..fd2d6b41f 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionMongoQueryServiceTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionMongoQueryServiceTest.kt @@ -406,7 +406,9 @@ internal class SubmissionMongoQueryServiceTest( submission = BasicDBObject.parse(serializationService.serialize(submission)), totalFiles = 6, conflictingFiles = 1, + conflictingPageTab = 0, deprecatedFiles = 10, + deprecatedPageTab = 2, reusedFiles = 2, currentIndex = 0, modificationTime = Instant.now(), diff --git a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt index 96bb184fe..5df126537 100644 --- a/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt +++ b/submission/persistence-mongo/src/test/kotlin/ac/uk/ebi/biostd/persistence/doc/service/SubmissionRequestMongoPersistenceServiceTest.kt @@ -161,7 +161,9 @@ class SubmissionRequestMongoPersistenceServiceTest( submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0" }.toString()), totalFiles = 5, conflictingFiles = 1, + conflictingPageTab = 0, deprecatedFiles = 10, + deprecatedPageTab = 3, reusedFiles = 2, currentIndex = 0, modificationTime = modificationTime, @@ -212,7 +214,9 @@ class SubmissionRequestMongoPersistenceServiceTest( submission = BasicDBObject.parse(jsonObj { "submission" to "S-BSST0" }.toString()), totalFiles = 5, conflictingFiles = 1, + conflictingPageTab = 0, deprecatedFiles = 10, + deprecatedPageTab = 2, reusedFiles = 2, currentIndex = 0, modificationTime = Instant.ofEpochMilli(1664981300), diff --git a/submission/submission-config/src/main/kotlin/ac/uk/ebi/biostd/common/properties/TaskProperties.kt b/submission/submission-config/src/main/kotlin/ac/uk/ebi/biostd/common/properties/TaskProperties.kt index 06b8b5e2b..ab22270ce 100644 --- a/submission/submission-config/src/main/kotlin/ac/uk/ebi/biostd/common/properties/TaskProperties.kt +++ b/submission/submission-config/src/main/kotlin/ac/uk/ebi/biostd/common/properties/TaskProperties.kt @@ -18,8 +18,9 @@ enum class Mode { INDEX, LOAD, INDEX_TO_CLEAN, - COPY, + VALIDATE, CLEAN, + COPY, CHECK_RELEASED, SAVE, FINALIZE, diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/config/SubmitterConfig.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/config/SubmitterConfig.kt index 5161f43ba..3a40c5499 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/config/SubmitterConfig.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/config/SubmitterConfig.kt @@ -23,6 +23,7 @@ import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestLoader import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestProcessor import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestReleaser import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestSaver +import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestValidator import ac.uk.ebi.biostd.submission.domain.submission.SubFolderResolver import ac.uk.ebi.biostd.submission.domain.submission.SubmissionProcessor import ac.uk.ebi.biostd.submission.domain.submission.SubmissionSubmitter @@ -56,7 +57,7 @@ import uk.ac.ebi.fire.client.integration.web.FireClient import uk.ac.ebi.serialization.common.FilesResolver import java.io.File -@Suppress("LongParameterList") +@Suppress("LongParameterList", "TooManyFunctions") @Configuration @Import( ServiceConfig::class, @@ -98,6 +99,20 @@ class SubmitterConfig( eventsPublisherService, ) + @Bean + fun requestValidator( + userPrivilegesService: IUserPrivilegesService, + eventsPublisherService: EventsPublisherService, + queryService: SubmissionPersistenceQueryService, + requestService: SubmissionRequestPersistenceService, + ): SubmissionRequestValidator = + SubmissionRequestValidator( + userPrivilegesService, + eventsPublisherService, + queryService, + requestService, + ) + @Bean fun requestLoader( eventsPublisherService: EventsPublisherService, @@ -189,8 +204,9 @@ class SubmitterConfig( persistenceService: SubmissionPersistenceService, submissionQueryService: ExtSubmissionQueryService, requestIndexer: SubmissionRequestIndexer, - requestToCleanIndexed: SubmissionRequestCleanIndexer, requestLoader: SubmissionRequestLoader, + requestToCleanIndexed: SubmissionRequestCleanIndexer, + requestValidator: SubmissionRequestValidator, requestProcessor: SubmissionRequestProcessor, submissionReleaser: SubmissionRequestReleaser, submissionCleaner: SubmissionRequestCleaner, @@ -202,8 +218,9 @@ class SubmitterConfig( requestService, persistenceService, requestIndexer, - requestToCleanIndexed, requestLoader, + requestToCleanIndexed, + requestValidator, requestProcessor, submissionReleaser, submissionCleaner, diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexer.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexer.kt index c01994261..7415eabde 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexer.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexer.kt @@ -1,9 +1,13 @@ package ac.uk.ebi.biostd.submission.domain.request +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.CONFLICTING +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.CONFLICTING_PAGE_TAB import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.DEPRECATED +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.DEPRECATED_PAGE_TAB import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.LOADED import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.REUSED +import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFileChanges import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService @@ -11,6 +15,7 @@ import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceS import ebi.ac.uk.extended.model.ExtFile import ebi.ac.uk.extended.model.ExtSubmission import ebi.ac.uk.extended.model.StorageMode +import ebi.ac.uk.extended.model.allPageTabFiles import ebi.ac.uk.extended.model.storageMode import ebi.ac.uk.model.RequestStatus import kotlinx.coroutines.flow.map @@ -40,13 +45,12 @@ class SubmissionRequestCleanIndexer( processId: String, ) { requestService.onRequest(accNo, version, RequestStatus.LOADED, processId) { - val (reused, deprecated, conflicting, activeVersion) = indexRequest(it.submission) - RqtUpdate(it.cleanIndexed(conflicting, deprecated, reused, activeVersion)) + RqtUpdate(it.cleanIndexed(indexRequest(it.submission))) } eventsPublisherService.requestIndexedToClean(accNo, version) } - internal suspend fun indexRequest(new: ExtSubmission): FilesCount { + internal suspend fun indexRequest(new: ExtSubmission): SubmissionRequestFileChanges { val current = queryService.findExtByAccNo(new.accNo, includeFileListFiles = true) if (current != null) { @@ -58,24 +62,34 @@ class SubmissionRequestCleanIndexer( return response } - return FilesCount(0, 0, 0, null) + return SubmissionRequestFileChanges(0, 0, 0, 0, 0, null) } private suspend fun indexToCleanFiles( new: ExtSubmission, newFiles: FilesRecords, current: ExtSubmission, - ): FilesCount { + ): SubmissionRequestFileChanges { val reusedIdx = AtomicInteger(0) val conflictIdx = AtomicInteger(0) + val conflictPageTabIdx = AtomicInteger(0) val deprecatedIdx = AtomicInteger(0) + val deprecatedPageTabIdx = AtomicInteger(0) + + fun fileUpdate( + idx: AtomicInteger, + file: ExtFile, + status: RequestFileStatus, + ) = SubRqtFile(new, idx.incrementAndGet(), file, status, true) serializationService.filesFlow(current) .mapNotNull { file -> when (newFiles.findMatch(file)) { - MatchType.CONFLICTING -> SubRqtFile(new, conflictIdx.incrementAndGet(), file, CONFLICTING, true) - MatchType.DEPRECATED -> SubRqtFile(new, deprecatedIdx.incrementAndGet(), file, DEPRECATED, true) - MatchType.REUSED -> SubRqtFile(new, reusedIdx.incrementAndGet(), file, REUSED, true) + MatchType.CONFLICTING -> fileUpdate(conflictIdx, file, CONFLICTING) + MatchType.CONFLICTING_PAGE_TAB -> fileUpdate(conflictPageTabIdx, file, CONFLICTING_PAGE_TAB) + MatchType.DEPRECATED -> fileUpdate(deprecatedIdx, file, DEPRECATED) + MatchType.DEPRECATED_PAGE_TAB -> fileUpdate(deprecatedPageTabIdx, file, DEPRECATED_PAGE_TAB) + MatchType.REUSED -> fileUpdate(reusedIdx, file, REUSED) } } .collect { @@ -83,15 +97,24 @@ class SubmissionRequestCleanIndexer( filesRequestService.saveSubmissionRequestFile(it) } - return FilesCount(reusedIdx.get(), deprecatedIdx.get(), conflictIdx.get(), current.version) + return SubmissionRequestFileChanges( + reusedIdx.get(), + deprecatedIdx.get(), + deprecatedPageTabIdx.get(), + conflictIdx.get(), + conflictPageTabIdx.get(), + current.version, + ) } private suspend fun summarizeFileRecords(new: ExtSubmission): FilesRecords { val response = mutableMapOf() + val pageTabFiles = new.allPageTabFiles.groupBy { it.md5 } + filesRequestService .getSubmissionRequestFiles(new.accNo, new.version, LOADED) .map { it.file } - .collect { response[it.filePath] = FileRecord(it.md5, new.storageMode) } + .collect { response[it.filePath] = FileRecord(it.md5, new.storageMode, pageTabFiles.containsKey(it.md5)) } return FilesRecords(response) } } @@ -100,33 +123,38 @@ class SubmissionRequestCleanIndexer( * Contains new submission file entries and storage type. */ private class FilesRecords( - val files: Map, + val newFiles: Map, ) { /** - * Validates if there is a entry in the current submission files with the given file Path (storage mode) but - * diferent Md5. + * Identifies and classifies the given file in one of the five categories: + * - DEPRECATED: The existing file is not present in the new version or the storage mode has changed + * - DEPRECATED_PAGE_TAB: The existing pagetab file is not present in the new version and storage mode has changed + * - CONFLICTING: The existing file is present in the new version but with different content + * - CONFLICTING_PAGE_TAB: The existing pagetab file is present in the new version but with different content + * - REUSED: The existing file hasn't changed in the new version, so it can be reused */ fun findMatch(existing: ExtFile): MatchType { - val newFile = files[existing.filePath] + val newFile = newFiles[existing.filePath] + val storageModeChanged = newFile?.storageMode != existing.storageMode + val md5Changed = newFile?.md5 != existing.md5 + val isPageTab = newFile?.isPageTab ?: false + return when { - newFile == null || newFile.storageMode != existing.storageMode -> MatchType.DEPRECATED - newFile.md5 != existing.md5 -> MatchType.CONFLICTING + newFile != null && storageModeChanged && isPageTab -> MatchType.DEPRECATED_PAGE_TAB + newFile == null || storageModeChanged -> MatchType.DEPRECATED + md5Changed && isPageTab -> MatchType.CONFLICTING_PAGE_TAB + md5Changed -> MatchType.CONFLICTING else -> MatchType.REUSED } } } -internal data class FilesCount( - val reused: Int, - val deprecated: Int, - val conflicting: Int, - val currentVersion: Int?, -) - private enum class MatchType { CONFLICTING, + CONFLICTING_PAGE_TAB, DEPRECATED, + DEPRECATED_PAGE_TAB, REUSED, } -private data class FileRecord(val md5: String, val storageMode: StorageMode) +private data class FileRecord(val md5: String, val storageMode: StorageMode, val isPageTab: Boolean) diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleaner.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleaner.kt index 00106cac6..5bac9264f 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleaner.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleaner.kt @@ -2,7 +2,9 @@ package ac.uk.ebi.biostd.submission.domain.request import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.CONFLICTING +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.CONFLICTING_PAGE_TAB import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.DEPRECATED +import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.DEPRECATED_PAGE_TAB import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService @@ -10,9 +12,9 @@ import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceS import ac.uk.ebi.biostd.persistence.filesystem.api.FileStorageService import ebi.ac.uk.extended.model.ExtFile import ebi.ac.uk.model.RequestStatus.CLEANED -import ebi.ac.uk.model.RequestStatus.INDEXED_CLEANED import ebi.ac.uk.model.RequestStatus.PERSISTED import ebi.ac.uk.model.RequestStatus.PROCESSED +import ebi.ac.uk.model.RequestStatus.VALIDATED import kotlinx.coroutines.flow.withIndex import mu.KotlinLogging import uk.ac.ebi.events.service.EventsPublisherService @@ -36,16 +38,20 @@ class SubmissionRequestCleaner( version: Int, processId: String, ) { - requestService.onRequest(accNo, version, INDEXED_CLEANED, processId) { + requestService.onRequest(accNo, version, VALIDATED, processId) { val previousVersion = it.previousVersion - if (previousVersion != null) cleanFiles(accNo, version, previousVersion = previousVersion, CONFLICTING) + if (previousVersion != null) { + cleanFiles(accNo, version, previousVersion = previousVersion, CONFLICTING) + cleanFiles(accNo, version, previousVersion = previousVersion, CONFLICTING_PAGE_TAB) + } + RqtUpdate(it.withNewStatus(CLEANED)) } eventsPublisherService.requestCleaned(accNo, version) } /** - * Executes the finalize or submission processing stage when files deprecated (file not used any more) from previous + * Executes the finalize or submission processing stage when files deprecated (file not used anymore) from previous * version are deleted. Note that submission is query wth negative version as new version has been already * persisted at this point. */ @@ -54,11 +60,15 @@ class SubmissionRequestCleaner( version: Int, processId: String, ) { - requestService.onRequest(accNo, version, PERSISTED, processId, { + requestService.onRequest(accNo, version, PERSISTED, processId) { val previousVersion = it.previousVersion - if (previousVersion != null) cleanFiles(accNo, version, previousVersion = -previousVersion, DEPRECATED) + if (previousVersion != null) { + cleanFiles(accNo, version, previousVersion = -previousVersion, DEPRECATED) + cleanFiles(accNo, version, previousVersion = -previousVersion, DEPRECATED_PAGE_TAB) + } + RqtUpdate(it.withNewStatus(PROCESSED)) - }) + } eventsPublisherService.submissionFinalized(accNo, version) } diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestValidator.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestValidator.kt new file mode 100644 index 000000000..9a0255e8f --- /dev/null +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestValidator.kt @@ -0,0 +1,61 @@ +package ac.uk.ebi.biostd.submission.domain.request + +import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest +import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate +import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService +import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService +import ebi.ac.uk.base.orFalse +import ebi.ac.uk.model.RequestStatus +import ebi.ac.uk.model.RequestStatus.INVALID +import ebi.ac.uk.model.RequestStatus.VALIDATED +import ebi.ac.uk.security.integration.components.IUserPrivilegesService +import mu.KotlinLogging +import uk.ac.ebi.events.service.EventsPublisherService + +private val logger = KotlinLogging.logger {} + +class SubmissionRequestValidator( + private val userPrivilegesService: IUserPrivilegesService, + private val eventsPublisherService: EventsPublisherService, + private val queryService: SubmissionPersistenceQueryService, + private val requestService: SubmissionRequestPersistenceService, +) { + suspend fun validateRequest( + accNo: String, + version: Int, + processId: String, + ) { + var requestStatus = INVALID + + requestService.onRequest(accNo, version, RequestStatus.INDEXED_CLEANED, processId) { + requestStatus = validateRequest(it) + RqtUpdate(it.withNewStatus(requestStatus)) + } + + if (requestStatus == VALIDATED) eventsPublisherService.requestValidated(accNo, version) + } + + internal suspend fun validateRequest(rqt: SubmissionRequest): RequestStatus { + val accNo = rqt.submission.accNo + val submitter = rqt.submission.submitter + val currentReleased = queryService.findCoreInfo(rqt.submission.accNo)?.released.orFalse() + + if (currentReleased && + rqt.hasFilesChanges && + userPrivilegesService.canUpdatePublicSubmission(submitter, accNo).not() + ) { + logger.error { "$accNo ${rqt.submission.owner} The user $submitter is not allowed to modify files" } + return INVALID + } + + return VALIDATED + } + + /** + * A submission request has file changes if: + * - Any file has been deleted (deprecatedFiles > 0) + * - Any file has been replaced (conflictingFiles > 0) + */ + private val SubmissionRequest.hasFilesChanges: Boolean + get() = deprecatedFiles > 0 || conflictingFiles > 0 +} diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtSubmissionSubmitter.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtSubmissionSubmitter.kt index 1d4e30b64..466a2ba49 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtSubmissionSubmitter.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtSubmissionSubmitter.kt @@ -3,6 +3,7 @@ package ac.uk.ebi.biostd.submission.domain.submitter import ac.uk.ebi.biostd.persistence.common.request.ExtSubmitRequest import ebi.ac.uk.extended.model.ExtSubmission +@Suppress("TooManyFunctions") interface ExtSubmissionSubmitter { suspend fun createRequest(rqt: ExtSubmitRequest): Pair @@ -21,6 +22,11 @@ interface ExtSubmissionSubmitter { version: Int, ) + suspend fun validateRequest( + accNo: String, + version: Int, + ) + suspend fun cleanRequest( accNo: String, version: Int, diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtendedSubmissionSubmitter.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtendedSubmissionSubmitter.kt index 1b65ffe16..5250b4dc7 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtendedSubmissionSubmitter.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/ExtendedSubmissionSubmitter.kt @@ -11,10 +11,12 @@ import ebi.ac.uk.model.RequestStatus.CLEANED import ebi.ac.uk.model.RequestStatus.FILES_COPIED import ebi.ac.uk.model.RequestStatus.INDEXED import ebi.ac.uk.model.RequestStatus.INDEXED_CLEANED +import ebi.ac.uk.model.RequestStatus.INVALID import ebi.ac.uk.model.RequestStatus.LOADED import ebi.ac.uk.model.RequestStatus.PERSISTED import ebi.ac.uk.model.RequestStatus.PROCESSED import ebi.ac.uk.model.RequestStatus.REQUESTED +import ebi.ac.uk.model.RequestStatus.VALIDATED import java.time.Duration.ofMinutes @Suppress("TooManyFunctions") @@ -93,11 +95,13 @@ class ExtendedSubmissionSubmitter( REQUESTED -> triggerAndWait(accNo, version) { indexRequest(accNo, version) } INDEXED -> triggerAndWait(accNo, version) { loadRequest(accNo, version) } LOADED -> triggerAndWait(accNo, version) { indexToCleanRequest(accNo, version) } - INDEXED_CLEANED -> triggerAndWait(accNo, version) { cleanRequest(accNo, version) } + INDEXED_CLEANED -> triggerAndWait(accNo, version) { validateRequest(accNo, version) } + VALIDATED -> triggerAndWait(accNo, version) { cleanRequest(accNo, version) } CLEANED -> triggerAndWait(accNo, version) { processRequest(accNo, version) } FILES_COPIED -> triggerAndWait(accNo, version) { checkReleased(accNo, version) } CHECK_RELEASED -> triggerAndWait(accNo, version) { localExtSubmissionSubmitter.saveRequest(accNo, version) } PERSISTED -> triggerAndWait(accNo, version) { finalizeRequest(accNo, version) } + INVALID -> error("Request accNo=$accNo, version=$version is in an invalid state") PROCESSED -> error("Request accNo=$accNo, version=$version has been already processed") } } diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/LocalExtSubmissionSubmitter.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/LocalExtSubmissionSubmitter.kt index 3bf267c50..fd6e82544 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/LocalExtSubmissionSubmitter.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/LocalExtSubmissionSubmitter.kt @@ -14,6 +14,7 @@ import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestLoader import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestProcessor import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestReleaser import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestSaver +import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestValidator import ac.uk.ebi.biostd.submission.domain.submission.SubmissionService.Companion.SYNC_SUBMIT_TIMEOUT import ebi.ac.uk.coroutines.waitUntil import ebi.ac.uk.extended.model.ExtSubmission @@ -22,10 +23,12 @@ import ebi.ac.uk.model.RequestStatus.CLEANED import ebi.ac.uk.model.RequestStatus.FILES_COPIED import ebi.ac.uk.model.RequestStatus.INDEXED import ebi.ac.uk.model.RequestStatus.INDEXED_CLEANED +import ebi.ac.uk.model.RequestStatus.INVALID import ebi.ac.uk.model.RequestStatus.LOADED import ebi.ac.uk.model.RequestStatus.PERSISTED import ebi.ac.uk.model.RequestStatus.PROCESSED import ebi.ac.uk.model.RequestStatus.REQUESTED +import ebi.ac.uk.model.RequestStatus.VALIDATED import mu.KotlinLogging import java.time.Duration.ofMinutes @@ -38,8 +41,9 @@ class LocalExtSubmissionSubmitter( private val requestService: SubmissionRequestPersistenceService, private val persistenceService: SubmissionPersistenceService, private val requestIndexer: SubmissionRequestIndexer, - private val requestToCleanIndexer: SubmissionRequestCleanIndexer, private val requestLoader: SubmissionRequestLoader, + private val requestToCleanIndexer: SubmissionRequestCleanIndexer, + private val requestValidator: SubmissionRequestValidator, private val requestProcessor: SubmissionRequestProcessor, private val requestReleaser: SubmissionRequestReleaser, private val requestCleaner: SubmissionRequestCleaner, @@ -67,18 +71,25 @@ class LocalExtSubmissionSubmitter( requestLoader.loadRequest(accNo, version, properties.processId) } - override suspend fun cleanRequest( + override suspend fun indexToCleanRequest( accNo: String, version: Int, ) { - requestCleaner.cleanCurrentVersion(accNo, version, properties.processId) + requestToCleanIndexer.indexRequest(accNo, version, properties.processId) } - override suspend fun indexToCleanRequest( + override suspend fun validateRequest( accNo: String, version: Int, ) { - requestToCleanIndexer.indexRequest(accNo, version, properties.processId) + requestValidator.validateRequest(accNo, version, properties.processId) + } + + override suspend fun cleanRequest( + accNo: String, + version: Int, + ) { + requestCleaner.cleanCurrentVersion(accNo, version, properties.processId) } override suspend fun processRequest( @@ -117,12 +128,14 @@ class LocalExtSubmissionSubmitter( REQUESTED -> indexRequest(accNo, version) INDEXED -> loadRequest(accNo, version) LOADED -> indexToCleanRequest(accNo, version) - INDEXED_CLEANED -> cleanRequest(accNo, version) + INDEXED_CLEANED -> validateRequest(accNo, version) + VALIDATED -> cleanRequest(accNo, version) CLEANED -> processRequest(accNo, version) FILES_COPIED -> checkReleased(accNo, version) CHECK_RELEASED -> saveRequest(accNo, version) PERSISTED -> finalizeRequest(accNo, version) - PROCESSED -> logger.info { "Submission $accNo, $version has been already proccessed." } + INVALID -> logger.info { "Submission $accNo, $version is in an invalid state" } + PROCESSED -> logger.info { "Submission $accNo, $version has been already processed." } } waitUntil(timeout = ofMinutes(SYNC_SUBMIT_TIMEOUT)) { requestService.isRequestCompleted(accNo, version) } diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/RemoteExtSubmissionSubmitter.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/RemoteExtSubmissionSubmitter.kt index f2484c1d8..0a05097da 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/RemoteExtSubmissionSubmitter.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/submitter/RemoteExtSubmissionSubmitter.kt @@ -44,6 +44,13 @@ class RemoteExtSubmissionSubmitter( executeRemotely(accNo, version, Mode.INDEX_TO_CLEAN) } + override suspend fun validateRequest( + accNo: String, + version: Int, + ) { + executeRemotely(accNo, version, Mode.VALIDATE) + } + override suspend fun cleanRequest( accNo: String, version: Int, diff --git a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt index 2b9518012..8147ba789 100644 --- a/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt +++ b/submission/submission-core/src/main/kotlin/ac/uk/ebi/biostd/submission/exceptions/InvalidPermissionsException.kt @@ -32,8 +32,3 @@ class UserCanNotDeleteSubmissions( user: String, accNos: List, ) : InvalidPermissionsException("The user $user is not allowed to delete the submissions ${accNos.joinToString(", ")}") - -class UserCanNotRelease( - accNo: String, - user: String, -) : InvalidPermissionsException("The user $user is not allowed to release the submission $accNo") diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/extended/LocalExtSubmissionSubmitterTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/extended/LocalExtSubmissionSubmitterTest.kt deleted file mode 100644 index 401915317..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/extended/LocalExtSubmissionSubmitterTest.kt +++ /dev/null @@ -1,335 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.extended - -import ac.uk.ebi.biostd.common.properties.ApplicationProperties -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.request.ExtSubmitRequest -import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ac.uk.ebi.biostd.persistence.filesystem.pagetab.PageTabService -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestCleanIndexer -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestCleaner -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestIndexer -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestLoader -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestProcessor -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestReleaser -import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestSaver -import ac.uk.ebi.biostd.submission.domain.submitter.LocalExtSubmissionSubmitter -import ebi.ac.uk.extended.model.ExtSubmission -import ebi.ac.uk.model.RequestStatus.CHECK_RELEASED -import ebi.ac.uk.model.RequestStatus.CLEANED -import ebi.ac.uk.model.RequestStatus.FILES_COPIED -import ebi.ac.uk.model.RequestStatus.INDEXED -import ebi.ac.uk.model.RequestStatus.INDEXED_CLEANED -import ebi.ac.uk.model.RequestStatus.LOADED -import ebi.ac.uk.model.RequestStatus.PERSISTED -import ebi.ac.uk.model.RequestStatus.REQUESTED -import ebi.ac.uk.test.basicExtSubmission -import io.mockk.clearAllMocks -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.mockkStatic -import io.mockk.slot -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import java.time.OffsetDateTime -import java.time.ZoneOffset.UTC - -@ExtendWith(MockKExtension::class) -internal class LocalExtSubmissionSubmitterTest( - @MockK private val properties: ApplicationProperties, - @MockK private val sub: ExtSubmission, - @MockK private val pageTabService: PageTabService, - @MockK private val requestService: SubmissionRequestPersistenceService, - @MockK private val persistenceService: SubmissionPersistenceService, - @MockK private val requestIndexer: SubmissionRequestIndexer, - @MockK private val requestCleanIndexer: SubmissionRequestCleanIndexer, - @MockK private val requestLoader: SubmissionRequestLoader, - @MockK private val requestProcessor: SubmissionRequestProcessor, - @MockK private val requestReleaser: SubmissionRequestReleaser, - @MockK private val requestCleaner: SubmissionRequestCleaner, - @MockK private val requestSaver: SubmissionRequestSaver, - @MockK private val subQueryService: ExtSubmissionQueryService, -) { - private val mockNow = OffsetDateTime.of(2020, 9, 21, 1, 2, 3, 4, UTC) - private val testInstance = - LocalExtSubmissionSubmitter( - properties, - pageTabService, - requestService, - persistenceService, - requestIndexer, - requestCleanIndexer, - requestLoader, - requestProcessor, - requestReleaser, - requestCleaner, - requestSaver, - subQueryService, - ) - - @AfterEach - fun afterEach() = clearAllMocks() - - @BeforeEach - fun beforeEach() { - mockkStatic(OffsetDateTime::class) - every { properties.processId } returns INSTANCE_ID - every { OffsetDateTime.now() } returns mockNow - } - - @Nested - inner class CreateRequest { - @Test - fun `create request`() = - runTest { - val submission = basicExtSubmission - val submissionRequestSlot = slot() - - coEvery { persistenceService.getNextVersion("S-TEST123") } returns 2 - coEvery { pageTabService.generatePageTab(submission) } returns submission - coEvery { requestService.createRequest(capture(submissionRequestSlot)) } returns ("S-TEST123" to 2) - - testInstance.createRequest(ExtSubmitRequest(submission, "user@test.org", "TMP_123")) - - val request = submissionRequestSlot.captured - coVerify(exactly = 1) { - pageTabService.generatePageTab(submission) - requestService.createRequest(request) - } - assertThat(request.submission).isEqualTo(submission.copy(version = 2)) - assertThat(request.draftKey).isEqualTo("TMP_123") - assertThat(request.notifyTo).isEqualTo("user@test.org") - assertThat(request.status).isEqualTo(REQUESTED) - assertThat(request.totalFiles).isEqualTo(0) - assertThat(request.currentIndex).isEqualTo(0) - assertThat(request.modificationTime).isEqualTo(mockNow) - } - } - - @Nested - inner class RequestStages { - @Test - fun `index request`() = - runTest { - coEvery { requestIndexer.indexRequest(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - - testInstance.indexRequest(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestIndexer.indexRequest(ACC_NO, VERSION, INSTANCE_ID) } - } - - @Test - fun `load request`() = - runTest { - coEvery { requestLoader.loadRequest(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - - testInstance.loadRequest(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestLoader.loadRequest(ACC_NO, VERSION, INSTANCE_ID) } - } - - @Test - fun `clean request`() = - runTest { - coEvery { requestCleaner.cleanCurrentVersion(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - - testInstance.cleanRequest(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestCleaner.cleanCurrentVersion(ACC_NO, VERSION, INSTANCE_ID) } - } - - @Test - fun `process request`() = - runTest { - coEvery { requestProcessor.processRequest(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - - testInstance.processRequest(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestProcessor.processRequest(ACC_NO, VERSION, INSTANCE_ID) } - } - - @Test - fun `check released`() = - runTest { - coEvery { requestReleaser.checkReleased(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - - testInstance.checkReleased(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestReleaser.checkReleased(ACC_NO, VERSION, INSTANCE_ID) } - } - - @Test - fun `save request`() = - runTest { - coEvery { requestSaver.saveRequest(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - - testInstance.saveRequest(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestSaver.saveRequest(ACC_NO, VERSION, INSTANCE_ID) } - } - - @Test - fun `finalize request`() = - runTest { - coEvery { requestCleaner.finalizeRequest(ACC_NO, VERSION, INSTANCE_ID) } answers { nothing } - coEvery { subQueryService.getExtendedSubmission(ACC_NO, includeFileListFiles = false) } returns sub - - testInstance.finalizeRequest(ACC_NO, VERSION) - - coVerify(exactly = 1) { requestCleaner.finalizeRequest(ACC_NO, VERSION, INSTANCE_ID) } - } - } - - @Nested - inner class HandleRequest { - @Test - fun `when requested`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns REQUESTED - coEvery { requestIndexer.indexRequest("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestIndexer.indexRequest("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when indexed`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns INDEXED - coEvery { requestLoader.loadRequest("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestLoader.loadRequest("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when loaded`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns LOADED - coEvery { requestCleanIndexer.indexRequest("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestCleanIndexer.indexRequest("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when indexed files to clean`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns INDEXED_CLEANED - coEvery { requestCleaner.cleanCurrentVersion("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestCleaner.cleanCurrentVersion("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when cleaned`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns CLEANED - coEvery { requestProcessor.processRequest("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestProcessor.processRequest("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when files copied`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns FILES_COPIED - coEvery { requestReleaser.checkReleased("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestReleaser.checkReleased("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when checked released`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns CHECK_RELEASED - coEvery { requestSaver.saveRequest("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestSaver.saveRequest("accNo", 1, INSTANCE_ID) - } - } - - @Test - fun `when persisted`() = - runTest { - coEvery { requestService.getRequestStatus("accNo", 1) } returns PERSISTED - coEvery { requestCleaner.finalizeRequest("accNo", 1, INSTANCE_ID) } answers { nothing } - coEvery { requestService.isRequestCompleted("accNo", 1) } returns true - coEvery { subQueryService.getExtendedSubmission("accNo", includeFileListFiles = false) } returns sub - - val result = testInstance.handleRequest("accNo", 1) - - assertThat(result).isEqualTo(sub) - coVerify(exactly = 1) { - requestService.getRequestStatus("accNo", 1) - requestCleaner.finalizeRequest("accNo", 1, INSTANCE_ID) - } - } - } - - private companion object { - const val ACC_NO = "S-BSST1" - const val INSTANCE_ID = "biostudies-prod" - const val VERSION = 1 - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexerTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexerTest.kt deleted file mode 100644 index 7ef7353c1..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanIndexerTest.kt +++ /dev/null @@ -1,256 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.CONFLICTING -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.DEPRECATED -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.LOADED -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.REUSED -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ebi.ac.uk.extended.model.ExtFile -import ebi.ac.uk.extended.model.ExtSubmission -import ebi.ac.uk.extended.model.NfsFile -import ebi.ac.uk.extended.model.StorageMode.FIRE -import ebi.ac.uk.extended.model.StorageMode.NFS -import io.mockk.Called -import io.mockk.clearAllMocks -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.mockkStatic -import io.mockk.slot -import io.mockk.verify -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService -import uk.ac.ebi.extended.serialization.service.ExtSerializationService -import uk.ac.ebi.extended.serialization.service.filesFlow - -@ExtendWith(MockKExtension::class) -class SubmissionRequestCleanIndexerTest( - @MockK val serializationService: ExtSerializationService, - @MockK val queryService: SubmissionPersistenceQueryService, - @MockK val fileRqtService: SubmissionRequestFilesPersistenceService, - @MockK val eventsPublisherService: EventsPublisherService, - @MockK val newSub: ExtSubmission, - @MockK val requestService: SubmissionRequestPersistenceService, - @MockK val currentSub: ExtSubmission, -) { - private val requestFileSlot = slot() - - private val testInstance = - SubmissionRequestCleanIndexer( - serializationService, - queryService, - fileRqtService, - requestService, - eventsPublisherService, - ) - - @Test - fun `when no current submission`() = - runTest { - every { newSub.accNo } returns ACC_NO - every { newSub.version } returns CURRENT_VERSION - coEvery { queryService.findExtByAccNo(ACC_NO, includeFileListFiles = true) } returns null - - val (reused, deprecated, conflicting, currentVersion) = testInstance.indexRequest(newSub) - - assertThat(currentVersion).isNull() - assertThat(reused).isZero() - assertThat(deprecated).isZero() - assertThat(conflicting).isZero() - verify { serializationService wasNot Called } - } - - @Nested - inner class WhenCurrentSubmission { - @BeforeEach - fun beforeEach() { - clearAllMocks() - - every { newSub.accNo } returns ACC_NO - every { newSub.version } returns NEW_VERSION - every { newSub.storageMode } returns STORAGE_MODE - - every { currentSub.storageMode } returns STORAGE_MODE - every { currentSub.accNo } returns ACC_NO - every { currentSub.version } returns CURRENT_VERSION - - coEvery { queryService.findExtByAccNo(ACC_NO, includeFileListFiles = true) } returns currentSub - } - - @Test - fun `when a file has the same md5 but diferent path so file need to be cleaned`( - @MockK newFile: ExtFile, - @MockK newRqtFile: SubmissionRequestFile, - @MockK file: NfsFile, - ) = runTest { - coEvery { - fileRqtService.getSubmissionRequestFiles( - ACC_NO, - NEW_VERSION, - LOADED, - ) - } returns flowOf(newRqtFile) - - every { newRqtFile.file } returns newFile - every { newFile.filePath } returns ONE_PATH - every { newFile.md5 } returns ONE_MD5 - - every { file.md5 } returns ONE_MD5 - every { file.filePath } returns ANOTHER_PATH - - mockkStatic(ExtSerializationService::filesFlow) - coEvery { serializationService.filesFlow(currentSub) } returns flowOf(file) - coEvery { fileRqtService.saveSubmissionRequestFile(any()) } coAnswers { nothing } - - val (reused, deprecated, conflicting, currentVersion) = testInstance.indexRequest(newSub) - - assertThat(currentVersion).isEqualTo(CURRENT_VERSION) - assertThat(reused).isZero() - assertThat(conflicting).isZero() - assertThat(deprecated).isOne() - coVerify { fileRqtService.saveSubmissionRequestFile(capture(requestFileSlot)) } - val requestFile = requestFileSlot.captured - assertThat(requestFile.status).isEqualTo(DEPRECATED) - assertThat(requestFile.file).isEqualTo(file) - } - - @Test - fun `when a file has the same md5 and path but different storage mode so file need to be cleaned`( - @MockK newFile: ExtFile, - @MockK newRqtFile: SubmissionRequestFile, - @MockK file: NfsFile, - ) = runTest { - coEvery { - fileRqtService.getSubmissionRequestFiles( - ACC_NO, - NEW_VERSION, - LOADED, - ) - } returns flowOf(newRqtFile) - - every { newRqtFile.file } returns newFile - every { newFile.filePath } returns ONE_PATH - every { newFile.md5 } returns ONE_MD5 - - every { file.md5 } returns ONE_MD5 - every { file.filePath } returns ONE_PATH - - mockkStatic(ExtSerializationService::filesFlow) - coEvery { serializationService.filesFlow(currentSub) } returns flowOf(file) - coEvery { fileRqtService.saveSubmissionRequestFile(any()) } coAnswers { nothing } - - every { newSub.storageMode } returns FIRE - - val (reused, deprecated, conflicting, currentVersion) = testInstance.indexRequest(newSub) - - assertThat(currentVersion).isEqualTo(CURRENT_VERSION) - assertThat(reused).isZero() - assertThat(deprecated).isOne() - assertThat(conflicting).isZero() - coVerify { fileRqtService.saveSubmissionRequestFile(capture(requestFileSlot)) } - val requestFile = requestFileSlot.captured - assertThat(requestFile.status).isEqualTo(DEPRECATED) - assertThat(requestFile.file).isEqualTo(file) - } - - @Test - fun `when a file of the current submission is re used`( - @MockK newFile: ExtFile, - @MockK newRqtFile: SubmissionRequestFile, - @MockK file: NfsFile, - ) = runTest { - coEvery { - fileRqtService.getSubmissionRequestFiles( - ACC_NO, - NEW_VERSION, - LOADED, - ) - } returns flowOf(newRqtFile) - - // Both new file and current submission file is the same - every { newRqtFile.file } returns newFile - every { newFile.filePath } returns ONE_PATH - every { newFile.md5 } returns ONE_MD5 - every { file.md5 } returns ONE_MD5 - every { file.filePath } returns ONE_PATH - - mockkStatic(ExtSerializationService::filesFlow) - coEvery { serializationService.filesFlow(currentSub) } returns flowOf(file) - coEvery { fileRqtService.saveSubmissionRequestFile(any()) } coAnswers { nothing } - - val (reused, deprecated, conflicting, currentVersion) = testInstance.indexRequest(newSub) - - assertThat(currentVersion).isEqualTo(CURRENT_VERSION) - assertThat(reused).isOne() - assertThat(deprecated).isZero() - assertThat(conflicting).isZero() - coVerify { fileRqtService.saveSubmissionRequestFile(capture(requestFileSlot)) } - - val requestFile = requestFileSlot.captured - assertThat(requestFile.status).isEqualTo(REUSED) - assertThat(requestFile.file).isEqualTo(file) - } - - @Test - fun `when a file of the current submission needs to be replaced`( - @MockK newFile: ExtFile, - @MockK newRqtFile: SubmissionRequestFile, - @MockK replacedFile: NfsFile, - ) = runTest { - coEvery { - fileRqtService.getSubmissionRequestFiles( - ACC_NO, - NEW_VERSION, - LOADED, - ) - } returns flowOf(newRqtFile) - - every { newRqtFile.file } returns newFile - every { newFile.filePath } returns ONE_PATH - every { newFile.md5 } returns ONE_PATH - - every { replacedFile.md5 } returns ANOTHER_MD5 - every { replacedFile.filePath } returns ONE_PATH - - mockkStatic(ExtSerializationService::filesFlow) - coEvery { serializationService.filesFlow(currentSub) } returns flowOf(replacedFile) - coEvery { fileRqtService.saveSubmissionRequestFile(any()) } coAnswers { nothing } - - val (reused, deprecated, conflicting, currentVersion) = testInstance.indexRequest(newSub) - - assertThat(currentVersion).isEqualTo(CURRENT_VERSION) - assertThat(reused).isZero() - assertThat(deprecated).isZero() - assertThat(conflicting).isOne() - coVerify { fileRqtService.saveSubmissionRequestFile(capture(requestFileSlot)) } - - val requestFile = requestFileSlot.captured - assertThat(requestFile.status).isEqualTo(CONFLICTING) - assertThat(requestFile.file).isEqualTo(replacedFile) - } - } - - private companion object { - const val ACC_NO = "abc" - const val NEW_VERSION = 2 - const val CURRENT_VERSION = 1 - val STORAGE_MODE = NFS - - const val ONE_PATH = "path1" - const val ANOTHER_PATH = "path2" - - const val ONE_MD5 = "md51" - const val ANOTHER_MD5 = "md52" - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanerTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanerTest.kt deleted file mode 100644 index 4334826e6..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestCleanerTest.kt +++ /dev/null @@ -1,116 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.CONFLICTING -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate -import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ac.uk.ebi.biostd.persistence.filesystem.service.StorageService -import ebi.ac.uk.extended.model.ExtFile -import ebi.ac.uk.extended.model.ExtSubmission -import ebi.ac.uk.extended.model.ExtSubmissionInfo -import ebi.ac.uk.extended.model.StorageMode.FIRE -import ebi.ac.uk.model.RequestStatus.CLEANED -import ebi.ac.uk.model.RequestStatus.INDEXED_CLEANED -import io.mockk.clearAllMocks -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.mockk -import io.mockk.mockkStatic -import io.mockk.slot -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService - -@ExtendWith(MockKExtension::class) -class SubmissionRequestCleanerTest( - @MockK private val queryService: SubmissionPersistenceQueryService, - @MockK private val storageService: StorageService, - @MockK private val eventsPublisherService: EventsPublisherService, - @MockK private val rqtService: SubmissionRequestPersistenceService, - @MockK private val filesService: SubmissionRequestFilesPersistenceService, -) { - private val testInstance = - SubmissionRequestCleaner( - concurrency = 1, - queryService, - storageService, - eventsPublisherService, - rqtService, - filesService, - ) - - @BeforeEach - fun beforeEach() { - mockkStatic("uk.ac.ebi.extended.serialization.service.ExtSerializationServiceExtKt") - } - - @AfterEach - fun afterEach() = clearAllMocks() - - @Test - fun cleanCurrentVersion( - @MockK sub: ExtSubmission, - @MockK previousSub: ExtSubmissionInfo, - @MockK request: SubmissionRequest, - @MockK cleanedRequest: SubmissionRequest, - @MockK file: ExtFile, - ) = runTest { - every { request.submission } returns sub - every { request.previousVersion } returns PREVIOUS_VERSION - every { sub.accNo } returns ACC_NO - every { sub.version } returns VERSION - - every { request.withNewStatus(CLEANED) } returns cleanedRequest - every { eventsPublisherService.requestCleaned(ACC_NO, VERSION) } answers { nothing } - - val requestFile = SubmissionRequestFile(ACC_NO, VERSION, 1, "path", file, CONFLICTING) - every { filesService.getSubmissionRequestFiles(ACC_NO, VERSION, CONFLICTING) } returns flowOf(requestFile) - - coEvery { storageService.deleteSubmissionFile(previousSub, file) } answers { nothing } - coEvery { queryService.getCoreInfoByAccNoAndVersion(ACC_NO, PREVIOUS_VERSION) } returns previousSub - coEvery { rqtService.updateRqtFile(requestFile.copy(status = RequestFileStatus.CLEANED)) } answers { nothing } - - coEvery { - rqtService.onRequest(ACC_NO, VERSION, INDEXED_CLEANED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(request) - } - - testInstance.cleanCurrentVersion(ACC_NO, VERSION, PROCESS_ID) - - coVerify(exactly = 1) { - storageService.deleteSubmissionFile(previousSub, file) - eventsPublisherService.requestCleaned(ACC_NO, VERSION) - request.withNewStatus(CLEANED) - rqtService.updateRqtFile(requestFile.copy(status = RequestFileStatus.CLEANED)) - } - } - - private fun mockSubmission(): ExtSubmission { - val mockSubmission = mockk() - every { mockSubmission.version } returns 2 - every { mockSubmission.accNo } returns "S-BSST1" - every { mockSubmission.storageMode } returns FIRE - every { mockSubmission.owner } returns "owner@mail.org" - return mockSubmission - } - - private companion object { - private val rqtSlot = slot RqtUpdate>() - const val PROCESS_ID = "biostudies-prod" - const val ACC_NO = "S-BSST1" - const val VERSION = 2 - const val PREVIOUS_VERSION = 1 - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestIndexerTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestIndexerTest.kt deleted file mode 100644 index 9e0e82ef2..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestIndexerTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ebi.ac.uk.base.Either.Companion.left -import ebi.ac.uk.extended.model.ExtSection -import ebi.ac.uk.extended.model.NfsFile -import ebi.ac.uk.model.RequestStatus -import ebi.ac.uk.test.basicExtSubmission -import io.github.glytching.junit.extension.folder.TemporaryFolder -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.slot -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService -import uk.ac.ebi.extended.serialization.service.ExtSerializationService - -@ExtendWith(MockKExtension::class, TemporaryFolderExtension::class) -class SubmissionRequestIndexerTest( - private val tempFolder: TemporaryFolder, - @MockK private val pendingRqt: SubmissionRequest, - @MockK private val eventsPublisherService: EventsPublisherService, - @MockK private val rqtService: SubmissionRequestPersistenceService, - @MockK private val filesRequestService: SubmissionRequestFilesPersistenceService, -) { - private val testInstance = - SubmissionRequestIndexer( - eventsPublisherService, - ExtSerializationService(), - rqtService, - filesRequestService, - ) - - @Test - fun `index request`() = - runTest { - val requestFileSlot = slot() - val file = tempFolder.createFile("requested.txt") - val extFile = NfsFile("dummy.txt", "Files/dummy.txt", file, file.absolutePath, "NOT_CALCULATED", -1) - val sub = basicExtSubmission.copy(section = ExtSection(type = "Study", files = listOf(left(extFile)))) - - every { pendingRqt.indexed(1) } returns pendingRqt - every { pendingRqt.submission } returns sub - every { eventsPublisherService.requestIndexed(ACC_NO, VERSION) } answers { nothing } - coEvery { - rqtService.onRequest(ACC_NO, VERSION, RequestStatus.REQUESTED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(pendingRqt) - } - - coEvery { filesRequestService.saveSubmissionRequestFile(capture(requestFileSlot)) } answers { nothing } - - testInstance.indexRequest(ACC_NO, VERSION, PROCESS_ID) - - val requestFile = requestFileSlot.captured - assertThat(requestFile.index).isEqualTo(1) - coVerify(exactly = 1) { - filesRequestService.saveSubmissionRequestFile(requestFile) - eventsPublisherService.requestIndexed(ACC_NO, VERSION) - } - } - - private companion object { - const val PROCESS_ID = "biostudies-prod" - const val ACC_NO = "S-BSST0" - const val VERSION = 1 - private val rqtSlot = slot RqtUpdate>() - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestLoaderTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestLoaderTest.kt deleted file mode 100644 index 6640d1ef9..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestLoaderTest.kt +++ /dev/null @@ -1,112 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.LOADED -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.RqtResponse -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ac.uk.ebi.biostd.submission.common.TEST_CONCURRENCY -import ebi.ac.uk.base.Either.Companion.left -import ebi.ac.uk.extended.model.ExtSection -import ebi.ac.uk.extended.model.NfsFile -import ebi.ac.uk.io.ext.md5 -import ebi.ac.uk.io.ext.size -import ebi.ac.uk.model.RequestStatus -import ebi.ac.uk.model.RequestStatus.INDEXED -import ebi.ac.uk.test.basicExtSubmission -import io.github.glytching.junit.extension.folder.TemporaryFolder -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.mockkStatic -import io.mockk.slot -import io.mockk.unmockkStatic -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService -import java.time.OffsetDateTime -import java.time.ZoneOffset.UTC - -@ExtendWith(MockKExtension::class, TemporaryFolderExtension::class) -class SubmissionRequestLoaderTest( - private val tempFolder: TemporaryFolder, - @MockK private val eventsPublisherService: EventsPublisherService, - @MockK private val requestService: SubmissionRequestPersistenceService, - @MockK private val filesService: SubmissionRequestFilesPersistenceService, -) { - private val mockNow = OffsetDateTime.of(2022, 10, 5, 0, 0, 1, 0, UTC) - private val fireTempDirPath = tempFolder.createDirectory("fire-temp") - private val testInstance = - SubmissionRequestLoader( - TEST_CONCURRENCY, - fireTempDirPath, - eventsPublisherService, - filesService, - requestService, - ) - - @BeforeEach - fun beforeEach() { - mockkStatic(OffsetDateTime::class) - every { OffsetDateTime.now() } returns mockNow - } - - @AfterEach - fun afterEach() { - unmockkStatic(OffsetDateTime::class) - } - - @Test - fun `load request`( - @MockK indexedRequest: SubmissionRequest, - ) = runTest { - val filSlot = slot() - val file = tempFolder.createFile("dummy.txt") - val nfsFile = NfsFile("dummy.txt", "Files/dummy.txt", file, file.absolutePath, "NOT_CALCULATED", -1) - val sub = basicExtSubmission.copy(section = ExtSection(type = "Study", files = listOf(left(nfsFile)))) - val indexedFile = - SubmissionRequestFile(sub.accNo, sub.version, 1, "dummy.txt", nfsFile, RequestFileStatus.INDEXED) - - every { indexedRequest.submission } returns sub - every { indexedRequest.currentIndex } returns 3 - every { indexedRequest.withNewStatus(RequestStatus.LOADED) } returns indexedRequest - every { eventsPublisherService.requestLoaded(sub.accNo, sub.version) } answers { nothing } - every { - filesService.getSubmissionRequestFiles( - sub.accNo, - sub.version, - RequestFileStatus.INDEXED, - ) - } returns flowOf(indexedFile) - coEvery { requestService.updateRqtFile(capture(filSlot)) } answers { nothing } - coEvery { - requestService.onRequest(sub.accNo, sub.version, INDEXED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { rqtSlot.captured.invoke(indexedRequest) } - - testInstance.loadRequest(sub.accNo, sub.version, PROCESS_ID) - - val requestFile = filSlot.captured - assertThat(requestFile.status).isEqualTo(LOADED) - assertThat(requestFile.file.md5).isEqualTo(file.md5()) - assertThat(requestFile.file.size).isEqualTo(file.size()) - - coVerify(exactly = 1) { - eventsPublisherService.requestLoaded(sub.accNo, sub.version) - } - } - - private companion object { - const val PROCESS_ID = "biostudies-prod" - val rqtSlot = slot RqtResponse>() - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestProcessorTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestProcessorTest.kt deleted file mode 100644 index c49d4d6a1..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestProcessorTest.kt +++ /dev/null @@ -1,90 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.COPIED -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.LOADED -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ac.uk.ebi.biostd.persistence.filesystem.api.FileStorageService -import ac.uk.ebi.biostd.submission.common.TEST_CONCURRENCY -import ebi.ac.uk.extended.model.ExtSubmission -import ebi.ac.uk.extended.model.FireFile -import ebi.ac.uk.extended.model.NfsFile -import ebi.ac.uk.model.RequestStatus.CLEANED -import ebi.ac.uk.model.RequestStatus.FILES_COPIED -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.clearAllMocks -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.slot -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService - -@ExtendWith(MockKExtension::class, TemporaryFolderExtension::class) -class SubmissionRequestProcessorTest( - @MockK private val storageService: FileStorageService, - @MockK private val eventsPublisherService: EventsPublisherService, - @MockK private val requestService: SubmissionRequestPersistenceService, - @MockK private val filesService: SubmissionRequestFilesPersistenceService, -) { - private val testInstance = - SubmissionRequestProcessor( - TEST_CONCURRENCY, - storageService, - eventsPublisherService, - requestService, - filesService, - ) - - @AfterEach - fun afterEach() = clearAllMocks() - - @Test - fun `process request`( - @MockK submission: ExtSubmission, - @MockK rqt: SubmissionRequest, - @MockK nfsFile: NfsFile, - @MockK savedFile: FireFile, - ) = runTest { - val nfsRqtFile = SubmissionRequestFile(ACC_NO, VERSION, 1, "test1.txt", nfsFile, LOADED) - every { rqt.submission } returns submission - every { rqt.currentIndex } returns 1 - every { submission.accNo } returns ACC_NO - every { submission.version } returns VERSION - every { eventsPublisherService.requestFilesCopied(ACC_NO, VERSION) } answers { nothing } - every { filesService.getSubmissionRequestFiles(ACC_NO, VERSION, LOADED) } returns flowOf(nfsRqtFile) - every { rqt.withNewStatus(FILES_COPIED) } returns rqt - coEvery { storageService.persistSubmissionFile(submission, nfsFile) } returns savedFile - coEvery { - requestService.onRequest(ACC_NO, VERSION, CLEANED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(rqt) - } - - coEvery { - requestService.updateRqtFile(nfsRqtFile.copy(file = savedFile, status = COPIED)) - } answers { nothing } - - testInstance.processRequest(ACC_NO, VERSION, PROCESS_ID) - - coVerify(exactly = 1) { - eventsPublisherService.requestFilesCopied(ACC_NO, VERSION) - } - } - - private companion object { - const val PROCESS_ID = "biostudies-prod" - const val ACC_NO = "ABC-123" - const val VERSION = 1 - val rqtSlot = slot RqtUpdate>() - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestReleaserTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestReleaserTest.kt deleted file mode 100644 index 67daaf44f..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestReleaserTest.kt +++ /dev/null @@ -1,273 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.COPIED -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.RELEASED -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.REUSED -import ac.uk.ebi.biostd.persistence.common.model.RequestFileStatus.UNRELEASED -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.RqtUpdate -import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ac.uk.ebi.biostd.persistence.filesystem.api.FileStorageService -import ac.uk.ebi.biostd.submission.common.TEST_CONCURRENCY -import ac.uk.ebi.biostd.submission.exceptions.UnreleasedSubmissionException -import ebi.ac.uk.asserts.assertThrows -import ebi.ac.uk.extended.model.ExtSubmission -import ebi.ac.uk.extended.model.FireFile -import ebi.ac.uk.extended.model.NfsFile -import ebi.ac.uk.extended.model.StorageMode -import ebi.ac.uk.model.RequestStatus.CHECK_RELEASED -import ebi.ac.uk.model.RequestStatus.FILES_COPIED -import io.github.glytching.junit.extension.folder.TemporaryFolderExtension -import io.mockk.called -import io.mockk.clearAllMocks -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.slot -import io.mockk.verify -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService -import uk.ac.ebi.extended.serialization.service.ExtSerializationService - -@ExtendWith(MockKExtension::class, TemporaryFolderExtension::class) -class SubmissionRequestReleaserTest( - @MockK private val storageService: FileStorageService, - @MockK private val eventsPublisherService: EventsPublisherService, - @MockK private val queryService: SubmissionPersistenceQueryService, - @MockK private val persistenceService: SubmissionPersistenceService, - @MockK private val requestService: SubmissionRequestPersistenceService, - @MockK private val filesService: SubmissionRequestFilesPersistenceService, -) { - private val testInstance = - SubmissionRequestReleaser( - TEST_CONCURRENCY, - storageService, - ExtSerializationService(), - eventsPublisherService, - queryService, - requestService, - filesService, - ) - - @AfterEach - fun afterEach() = clearAllMocks() - - @Test - fun `check released when release`( - @MockK submission: ExtSubmission, - @MockK rqt: SubmissionRequest, - @MockK nfsFile: NfsFile, - @MockK releasedFile: FireFile, - @MockK fireFile: FireFile, - ) = runTest { - val relPath = "sub-relpath" - val secretKey = "secret-key" - val mode = StorageMode.FIRE - - val nfsRqtFile = SubmissionRequestFile(ACC_NO, VERSION, 1, "test1.txt", nfsFile, COPIED) - val fireRqtFile = SubmissionRequestFile(ACC_NO, VERSION, 2, "test2.txt", fireFile, COPIED) - - every { rqt.submission } returns submission - every { rqt.currentIndex } returns 1 - every { submission.accNo } returns ACC_NO - every { submission.version } returns VERSION - every { submission.released } returns true - every { submission.relPath } returns relPath - every { submission.secretKey } returns secretKey - every { submission.storageMode } returns mode - every { eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) } answers { nothing } - every { filesService.getSubmissionRequestFiles(ACC_NO, VERSION, COPIED) } returns - flowOf( - nfsRqtFile, - fireRqtFile, - ) - coEvery { storageService.releaseSubmissionFile(submission, fireFile) } returns fireFile - coEvery { storageService.releaseSubmissionFile(submission, nfsFile) } returns releasedFile - every { rqt.withNewStatus(CHECK_RELEASED) } returns rqt - - coEvery { - requestService.updateRqtFile( - nfsRqtFile.copy( - file = releasedFile, - status = RELEASED, - ), - ) - } answers { nothing } - coEvery { requestService.updateRqtFile(fireRqtFile.copy(status = RELEASED)) } answers { nothing } - - coEvery { - requestService.onRequest(ACC_NO, VERSION, FILES_COPIED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(rqt) - } - - testInstance.checkReleased(ACC_NO, VERSION, PROCESS_ID) - - coVerify(exactly = 1) { - storageService.releaseSubmissionFile(submission, nfsFile) - eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) - } - } - - @Test - fun `check released when not released and no previous version`( - @MockK rqt: SubmissionRequest, - @MockK submission: ExtSubmission, - ) = runTest { - every { rqt.submission } returns submission - every { submission.released } returns false - every { rqt.withNewStatus(CHECK_RELEASED) } returns rqt - every { eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) } answers { nothing } - - coEvery { queryService.findCoreInfo(ACC_NO) } returns null - coEvery { - requestService.onRequest(ACC_NO, VERSION, FILES_COPIED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(rqt) - } - - testInstance.checkReleased(ACC_NO, VERSION, PROCESS_ID) - - verify { - storageService wasNot called - persistenceService wasNot called - } - coVerify(exactly = 1) { - eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) - } - } - - @Test - fun `check released when not released and previous version was private`( - @MockK rqt: SubmissionRequest, - @MockK current: ExtSubmission, - @MockK submission: ExtSubmission, - ) = runTest { - every { rqt.submission } returns submission - every { submission.released } returns false - every { current.released } returns false - every { rqt.withNewStatus(CHECK_RELEASED) } returns rqt - every { eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) } answers { nothing } - - coEvery { queryService.findCoreInfo(ACC_NO) } returns current - coEvery { - requestService.onRequest(ACC_NO, VERSION, FILES_COPIED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(rqt) - } - - testInstance.checkReleased(ACC_NO, VERSION, PROCESS_ID) - - verify { - storageService wasNot called - persistenceService wasNot called - } - coVerify(exactly = 1) { - eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) - } - } - - @Test - fun `check released when not released and previous version was public`( - @MockK current: ExtSubmission, - @MockK submission: ExtSubmission, - @MockK rqt: SubmissionRequest, - @MockK nfsFile: NfsFile, - @MockK fireFile: FireFile, - @MockK suppressedNfsFile: NfsFile, - @MockK suppressedFireFile: FireFile, - ) = runTest { - val relPath = "sub-relpath" - val secretKey = "secret-key" - val mode = StorageMode.FIRE - - val nfsRqtFile = SubmissionRequestFile(ACC_NO, VERSION, 1, "test1.txt", nfsFile, REUSED) - val fireRqtFile = SubmissionRequestFile(ACC_NO, VERSION, 2, "test2.txt", fireFile, REUSED) - - every { current.released } returns true - every { fireFile.published } returns true - every { rqt.submission } returns submission - every { rqt.currentIndex } returns 1 - every { submission.accNo } returns ACC_NO - every { submission.version } returns VERSION - every { submission.released } returns false - every { submission.relPath } returns relPath - every { submission.secretKey } returns secretKey - every { submission.storageMode } returns mode - every { eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) } answers { nothing } - every { filesService.getSubmissionRequestFiles(ACC_NO, VERSION, REUSED) } returns - flowOf( - nfsRqtFile, - fireRqtFile, - ) - coEvery { queryService.findCoreInfo(ACC_NO) } returns current - coEvery { storageService.unReleaseSubmissionFile(submission, nfsFile) } returns suppressedNfsFile - coEvery { storageService.unReleaseSubmissionFile(submission, fireFile) } returns suppressedFireFile - every { rqt.withNewStatus(CHECK_RELEASED) } returns rqt - - coEvery { - requestService.updateRqtFile( - nfsRqtFile.copy( - file = suppressedNfsFile, - status = UNRELEASED, - ), - ) - } answers { nothing } - - coEvery { - requestService.updateRqtFile( - fireRqtFile.copy( - file = suppressedFireFile, - status = UNRELEASED, - ), - ) - } answers { nothing } - - coEvery { - requestService.onRequest(ACC_NO, VERSION, FILES_COPIED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { - rqtSlot.captured.invoke(rqt) - } - - testInstance.checkReleased(ACC_NO, VERSION, PROCESS_ID) - - coVerify(exactly = 1) { - storageService.unReleaseSubmissionFile(submission, nfsFile) - storageService.unReleaseSubmissionFile(submission, fireFile) - eventsPublisherService.requestCheckedRelease(ACC_NO, VERSION) - } - } - - @Test - fun `generate ftp links for private submission`( - @MockK submission: ExtSubmission, - ) = runTest { - every { submission.released } returns false - coEvery { queryService.getExtByAccNo(ACC_NO, includeFileListFiles = true) } returns submission - - val exception = assertThrows { testInstance.generateFtpLinks(ACC_NO) } - - assertThat(exception.message).isEqualTo("Can't generate FTP links for a private submission") - coVerify { - storageService wasNot called - } - } - - private companion object { - const val ACC_NO = "S-TEST123" - const val VERSION = 1 - const val PROCESS_ID = "biostudies-prod" - private val rqtSlot = slot RqtUpdate>() - } -} diff --git a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestSaverTest.kt b/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestSaverTest.kt deleted file mode 100644 index 7eaa1873a..000000000 --- a/submission/submission-core/src/test/kotlin/ac/uk/ebi/biostd/submission/domain/request/SubmissionRequestSaverTest.kt +++ /dev/null @@ -1,102 +0,0 @@ -package ac.uk.ebi.biostd.submission.domain.request - -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequest -import ac.uk.ebi.biostd.persistence.common.model.SubmissionRequestFile -import ac.uk.ebi.biostd.persistence.common.service.RqtResponse -import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestFilesPersistenceService -import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService -import ebi.ac.uk.extended.model.ExtFile -import ebi.ac.uk.extended.model.ExtFileType.FILE -import ebi.ac.uk.extended.model.ExtSubmission -import ebi.ac.uk.extended.model.NfsFile -import ebi.ac.uk.model.RequestStatus.CHECK_RELEASED -import ebi.ac.uk.model.RequestStatus.PERSISTED -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.junit5.MockKExtension -import io.mockk.slot -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import uk.ac.ebi.events.service.EventsPublisherService -import uk.ac.ebi.extended.serialization.service.FileProcessingService -import java.io.File - -@ExtendWith(MockKExtension::class) -internal class SubmissionRequestSaverTest( - @MockK val requestService: SubmissionRequestPersistenceService, - @MockK val processingService: FileProcessingService, - @MockK val persistenceService: SubmissionPersistenceService, - @MockK val filesService: SubmissionRequestFilesPersistenceService, - @MockK val eventsPublisherService: EventsPublisherService, -) { - private val testInstance = - SubmissionRequestSaver( - requestService, - processingService, - persistenceService, - filesService, - eventsPublisherService, - ) - - @Test - fun saveRequest( - @MockK request: SubmissionRequest, - @MockK submission: ExtSubmission, - @MockK subFile: ExtFile, - @MockK requestFile: SubmissionRequestFile, - @MockK updatedFile: File, - ) = runTest { - val filePath = "the-file-path" - val notifyTo = "user@ebi.ac.uk" - val updatedSubFile = NfsFile("file.txt", "Files/file.txt", updatedFile, "file", "md5", 1, type = FILE) - - every { subFile.attributes } returns emptyList() - every { eventsPublisherService.submissionPersisted(ACC_NO, VERSION) } answers { nothing } - every { eventsPublisherService.submissionSubmitted(ACC_NO, notifyTo) } answers { nothing } - coEvery { persistenceService.expirePreviousVersions(ACC_NO) } answers { nothing } - coEvery { persistenceService.saveSubmission(submission) } answers { submission } - - every { submission.accNo } answers { ACC_NO } - every { submission.version } answers { VERSION } - every { subFile.filePath } returns filePath - - coEvery { - requestService.onRequest(ACC_NO, VERSION, CHECK_RELEASED, PROCESS_ID, capture(rqtSlot)) - } coAnswers { rqtSlot.captured.invoke(request) } - - every { request.withNewStatus(PERSISTED) } returns request - every { request.submission } answers { submission } - every { request.notifyTo } answers { notifyTo } - every { requestFile.file } returns updatedSubFile - - coEvery { filesService.getSubmissionRequestFile(ACC_NO, VERSION, filePath) } returns requestFile - - var newFile: ExtFile? = null - coEvery { processingService.processFiles(submission, any()) } coAnswers { - newFile = secondArg ExtFile>()(subFile) - submission - } - - testInstance.saveRequest(ACC_NO, VERSION, PROCESS_ID) - - assertThat(newFile).isEqualTo(updatedSubFile) - coVerify(exactly = 1) { - eventsPublisherService.submissionSubmitted(ACC_NO, notifyTo) - eventsPublisherService.submissionPersisted(ACC_NO, VERSION) - persistenceService.expirePreviousVersions(ACC_NO) - persistenceService.saveSubmission(submission) - } - } - - private companion object { - val ACC_NO = "ABC-123" - val VERSION = 1 - const val PROCESS_ID = "biostudies-prod" - val rqtSlot = slot RqtResponse>() - } -} diff --git a/submission/submission-handlers/src/test/kotlin/ac/uk/ebi/biostd/handlers/exception/CustomErrorHandlerTest.kt b/submission/submission-handlers/src/test/kotlin/ac/uk/ebi/biostd/handlers/exception/CustomErrorHandlerTest.kt index 4464751a3..2861d2524 100644 --- a/submission/submission-handlers/src/test/kotlin/ac/uk/ebi/biostd/handlers/exception/CustomErrorHandlerTest.kt +++ b/submission/submission-handlers/src/test/kotlin/ac/uk/ebi/biostd/handlers/exception/CustomErrorHandlerTest.kt @@ -33,7 +33,7 @@ class CustomErrorHandlerTest( assertFailsWith { testInstance.handleError(exception) } val alert = alertSlot.captured - assertThat(alert).isEqualToComparingFieldByField(expectedAlert) + assertThat(alert).usingRecursiveComparison().isEqualTo(expectedAlert) coVerify(exactly = 1) { notificationsSender.send(alert) } } } diff --git a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt index 802a9b629..2f83613e2 100644 --- a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt +++ b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/integration/components/IUserPrivilegesService.kt @@ -27,6 +27,11 @@ interface IUserPrivilegesService { accNo: String, ): Boolean + suspend fun canUpdatePublicSubmission( + submitter: String, + accNo: String, + ): Boolean + fun canSubmitExtended(submitter: String): Boolean fun canRelease(email: String): Boolean diff --git a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt index 8e05a6704..e5f2fd823 100644 --- a/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt +++ b/submission/submission-security/src/main/kotlin/ebi/ac/uk/security/service/UserPrivilegesService.kt @@ -4,6 +4,7 @@ import ac.uk.ebi.biostd.persistence.common.model.AccessType import ac.uk.ebi.biostd.persistence.common.model.AccessType.ATTACH import ac.uk.ebi.biostd.persistence.common.model.AccessType.DELETE import ac.uk.ebi.biostd.persistence.common.model.AccessType.UPDATE +import ac.uk.ebi.biostd.persistence.common.model.AccessType.UPDATE_PUBLIC import ac.uk.ebi.biostd.persistence.common.service.SubmissionMetaQueryService import ac.uk.ebi.biostd.persistence.common.service.UserPermissionsService import ac.uk.ebi.biostd.persistence.repositories.AccessTagDataRepo @@ -65,6 +66,13 @@ internal class UserPrivilegesService( hasPermissions(submitter, accNo, DELETE) } + override suspend fun canUpdatePublicSubmission( + submitter: String, + accNo: String, + ): Boolean { + return hasPermissions(submitter, accNo, UPDATE_PUBLIC) + } + override fun canRelease(email: String): Boolean = isSuperUser(email) override fun canUpdateReleaseDate(email: String): Boolean = isSuperUser(email) diff --git a/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/ProfileServiceTest.kt b/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/ProfileServiceTest.kt index 5e440390c..6d7a76531 100644 --- a/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/ProfileServiceTest.kt +++ b/submission/submission-security/src/test/kotlin/ebi/ac/uk/security/service/ProfileServiceTest.kt @@ -73,7 +73,7 @@ class ProfileServiceTest(temporaryFolder: TemporaryFolder) { val (user, token) = testInstance.getUserProfile(testUser, "a token") - assertThat(user).isEqualToComparingFieldByField(expectedUser) + assertThat(user).usingRecursiveComparison().isEqualTo(expectedUser) assertThat(token).isEqualTo("a token") } } diff --git a/submission/submission-task/src/main/kotlin/uk/ac/ebi/biostd/submission/SubmissionApp.kt b/submission/submission-task/src/main/kotlin/uk/ac/ebi/biostd/submission/SubmissionApp.kt index ba768426c..ee5c85127 100644 --- a/submission/submission-task/src/main/kotlin/uk/ac/ebi/biostd/submission/SubmissionApp.kt +++ b/submission/submission-task/src/main/kotlin/uk/ac/ebi/biostd/submission/SubmissionApp.kt @@ -10,6 +10,7 @@ import ac.uk.ebi.biostd.common.properties.Mode.INDEX import ac.uk.ebi.biostd.common.properties.Mode.INDEX_TO_CLEAN import ac.uk.ebi.biostd.common.properties.Mode.LOAD import ac.uk.ebi.biostd.common.properties.Mode.SAVE +import ac.uk.ebi.biostd.common.properties.Mode.VALIDATE import ac.uk.ebi.biostd.common.properties.TaskProperties import ac.uk.ebi.biostd.submission.config.SubmissionConfig import ac.uk.ebi.biostd.submission.domain.submitter.ExtSubmissionSubmitter @@ -67,6 +68,7 @@ class Execute( INDEX -> submissionSubmitter.indexRequest(accNo, version) LOAD -> submissionSubmitter.loadRequest(accNo, version) INDEX_TO_CLEAN -> submissionSubmitter.indexToCleanRequest(accNo, version) + VALIDATE -> submissionSubmitter.validateRequest(accNo, version) CLEAN -> submissionSubmitter.cleanRequest(accNo, version) COPY -> submissionSubmitter.processRequest(accNo, version) CHECK_RELEASED -> submissionSubmitter.checkReleased(accNo, version) diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/files/UserFileApiTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/files/UserFileApiTest.kt index 427b9a284..816893626 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/files/UserFileApiTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/files/UserFileApiTest.kt @@ -6,7 +6,6 @@ import ac.uk.ebi.biostd.itest.entities.TestUser import ac.uk.ebi.biostd.itest.itest.ITestListener.Companion.tempFolder import ac.uk.ebi.biostd.itest.itest.getWebClient import ebi.ac.uk.api.UserFile -import ebi.ac.uk.api.UserFileType import ebi.ac.uk.api.UserFileType.DIR import ebi.ac.uk.api.UserFileType.FILE import ebi.ac.uk.api.security.RegisterRequest @@ -111,7 +110,7 @@ class UserFileApiTest( relativePath: String, ) { assertThat(resultFile.name).isEqualTo(file.name) - assertThat(resultFile.type).isEqualTo(UserFileType.FILE) + assertThat(resultFile.type).isEqualTo(FILE) assertThat(resultFile.size).isEqualTo(file.length()) assertThat(resultFile.path).isEqualTo(Paths.get("user").resolve(relativePath).toString()) assertThat(file).hasContent(downloadFile.readText()) diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt index 43f676330..a3d588945 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/query/SubmissionListApiTest.kt @@ -74,7 +74,7 @@ class SubmissionListApiTest( ), ) - assertThat(submissionList).hasOnlyOneElementSatisfying { + assertThat(submissionList).satisfiesOnlyOnce { assertThat(it.accno).isEqualTo("LIST-API-17") assertThat(it.version).isEqualTo(1) assertThat(it.method).isEqualTo(PAGE_TAB) @@ -92,7 +92,7 @@ class SubmissionListApiTest( ), ) - assertThat(submissionList).hasOnlyOneElementSatisfying { + assertThat(submissionList).satisfiesOnlyOnce { assertThat(it.accno).isEqualTo("LIST-API-27") assertThat(it.version).isEqualTo(1) assertThat(it.method).isEqualTo(SubmissionMethod.FILE) @@ -110,7 +110,7 @@ class SubmissionListApiTest( ), ) - assertThat(submissionList).hasOnlyOneElementSatisfying { + assertThat(submissionList).satisfiesOnlyOnce { assertThat(it.title).contains("list-api-keyword-20") } } @@ -163,7 +163,7 @@ class SubmissionListApiTest( ), ) - assertThat(submissionList).hasOnlyOneElementSatisfying { + assertThat(submissionList).satisfiesOnlyOnce { assertThat(it.accno).isEqualTo("SECT-123") assertThat(it.version).isEqualTo(1) assertThat(it.method).isEqualTo(PAGE_TAB) @@ -187,7 +187,7 @@ class SubmissionListApiTest( assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() val submissionTitleList = webClient.getSubmissions(mapOf("keywords" to "secTitle")) - assertThat(submissionTitleList).hasOnlyOneElementSatisfying { + assertThat(submissionTitleList).satisfiesOnlyOnce { assertThat(it.accno).isEqualTo("SECT-124") assertThat(it.version).isEqualTo(1) assertThat(it.method).isEqualTo(PAGE_TAB) @@ -218,7 +218,7 @@ class SubmissionListApiTest( ), ) - assertThat(submissionList).hasOnlyOneElementSatisfying { + assertThat(submissionList).satisfiesOnlyOnce { assertThat(it.accno).isEqualTo("SECT-125") assertThat(it.version).isEqualTo(1) assertThat(it.method).isEqualTo(PAGE_TAB) diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/MultipartFileSubmissionApiTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/MultipartFileSubmissionApiTest.kt index 07c3aabf6..e1c55c1c2 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/MultipartFileSubmissionApiTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/MultipartFileSubmissionApiTest.kt @@ -111,7 +111,6 @@ class MultipartFileSubmissionApiTest( } } } - val config = SubmissionFilesConfig(listOf(fileList, tempFolder.createFile("SomeFile.txt")), storageMode) val filesConfig = SubmissionFilesConfig(listOf(fileList, tempFolder.createFile("SomeFile.txt")), storageMode) diff --git a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/ResubmissionApiTest.kt b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/ResubmissionApiTest.kt index 49d9ae4f5..d2a5fbc9b 100644 --- a/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/ResubmissionApiTest.kt +++ b/submission/submission-webapp/src/itest/kotlin/ac/uk/ebi/biostd/itest/test/submission/submit/ResubmissionApiTest.kt @@ -5,28 +5,27 @@ import ac.uk.ebi.biostd.client.integration.web.BioWebClient import ac.uk.ebi.biostd.itest.common.SecurityTestService import ac.uk.ebi.biostd.itest.entities.RegularUser import ac.uk.ebi.biostd.itest.entities.SuperUser -import ac.uk.ebi.biostd.itest.itest.ITestListener.Companion.ftpPath import ac.uk.ebi.biostd.itest.itest.ITestListener.Companion.submissionPath import ac.uk.ebi.biostd.itest.itest.ITestListener.Companion.tempFolder import ac.uk.ebi.biostd.itest.itest.getWebClient +import ac.uk.ebi.biostd.persistence.common.model.AccessType.UPDATE_PUBLIC import ac.uk.ebi.biostd.persistence.common.service.SubmissionPersistenceQueryService -import ac.uk.ebi.biostd.persistence.doc.commons.ExtendedUpdate -import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocSubmissionFields.SUB_ACC_NO -import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocSubmissionFields.SUB_RELEASE_TIME -import ac.uk.ebi.biostd.persistence.doc.db.converters.shared.DocSubmissionFields.SUB_VERSION -import ac.uk.ebi.biostd.persistence.doc.model.DocSubmission +import ac.uk.ebi.biostd.persistence.common.service.SubmissionRequestPersistenceService import ac.uk.ebi.biostd.submission.config.FilePersistenceConfig import ebi.ac.uk.asserts.assertThat +import ebi.ac.uk.coroutines.waitUntil import ebi.ac.uk.dsl.tsv.line import ebi.ac.uk.dsl.tsv.tsv -import ebi.ac.uk.io.FileUtils import ebi.ac.uk.io.ext.createFile +import ebi.ac.uk.io.ext.createOrReplaceFile +import ebi.ac.uk.model.RequestStatus.INVALID import ebi.ac.uk.util.date.toStringDate -import kotlinx.coroutines.reactor.awaitSingleOrNull import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat +import org.awaitility.Durations.TWO_SECONDS import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.springframework.beans.factory.annotation.Autowired @@ -34,12 +33,9 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.web.server.LocalServerPort import org.springframework.context.annotation.Import import org.springframework.data.mongodb.core.ReactiveMongoTemplate -import org.springframework.data.mongodb.core.query.Criteria.where -import org.springframework.data.mongodb.core.query.Query import org.springframework.test.context.junit.jupiter.SpringExtension import java.io.File import java.time.OffsetDateTime -import java.time.ZoneOffset.UTC @Import(FilePersistenceConfig::class) @ExtendWith(SpringExtension::class) @@ -47,6 +43,7 @@ import java.time.ZoneOffset.UTC class ResubmissionApiTest( @Autowired val mongoTemplate: ReactiveMongoTemplate, @Autowired val securityTestService: SecurityTestService, + @Autowired val requestRepository: SubmissionRequestPersistenceService, @Autowired val submissionRepository: SubmissionPersistenceQueryService, @LocalServerPort val serverPort: Int, ) { @@ -60,249 +57,395 @@ class ResubmissionApiTest( webClient = getWebClient(serverPort, SuperUser) } - @Test - fun `5-1 resubmit existing submission`() = - runTest { - val submission = - tsv { - line("Submission", "S-RSTST1") - line("Title", "Simple Submission With Files") - line("ReleaseDate", OffsetDateTime.now().toStringDate()) - line() - - line("Study") - line("Type", "Experiment") - line("File List", "file-list.tsv") - line() - - line("File", "file section.doc") - line("Type", "test") - line() - - line("Experiment", "Exp1") - line("Type", "Subsection") - line() - - line("File", "fileSubSection.txt") - line("Type", "Attached") - line() - }.toString() - - val fileListContent = - tsv { - line("Files", "Type") - line("a/fileFileList.pdf", "inner") - line("a", "folder") - }.toString() - - webClient.uploadFiles( - listOf( - tempFolder.createFile("fileSubSection.txt", "content"), - tempFolder.createFile("file-list.tsv", fileListContent), - tempFolder.createFile("file section.doc", "doc content"), - ), - ) - webClient.uploadFiles(listOf(tempFolder.createFile("fileFileList.pdf", "pdf content")), "a") - assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() - - val submitted = submissionRepository.getExtByAccNo("S-RSTST1") - assertThat(submitted.version).isEqualTo(1) - assertThat(File("$submissionPath/${submitted.relPath}/Files/file section.doc")).hasContent("doc content") - assertThat(File("$submissionPath/${submitted.relPath}/Files/fileSubSection.txt")).hasContent("content") - assertThat(File("$submissionPath/${submitted.relPath}/Files/a/fileFileList.pdf")).hasContent("pdf content") + @Nested + inner class Resubmit { + @Test + fun `5-1 resubmit private existing submission`() = + runTest { + val submission = + tsv { + line("Submission", "S-RSTST1") + line("Title", "Simple Submission With Files") + line("ReleaseDate", "2124-07-16") + line() + + line("Study") + line("Type", "Experiment") + line("File List", "file-list.tsv") + line() + + line("File", "file section.doc") + line("Type", "test") + line() + + line("Experiment", "Exp1") + line("Type", "Subsection") + line() + + line("File", "fileSubSection.txt") + line("Type", "Attached") + line() + }.toString() + + val fileListContent = + tsv { + line("Files", "Type") + line("a/fileFileList.pdf", "inner") + line("a", "folder") + }.toString() + + webClient.uploadFiles( + listOf( + tempFolder.createFile("fileSubSection.txt", "content"), + tempFolder.createFile("file-list.tsv", fileListContent), + tempFolder.createFile("file section.doc", "doc content"), + ), + ) + webClient.uploadFiles(listOf(tempFolder.createFile("fileFileList.pdf", "pdf content")), "a") + assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() + + val sub = submissionRepository.getExtByAccNo("S-RSTST1") + assertThat(sub.version).isEqualTo(1) + assertThat(File("$submissionPath/${sub.relPath}/Files/file section.doc")).hasContent("doc content") + assertThat(File("$submissionPath/${sub.relPath}/Files/fileSubSection.txt")).hasContent("content") + assertThat(File("$submissionPath/${sub.relPath}/Files/a/fileFileList.pdf")).hasContent("pdf content") + + val changedFile = tempFolder.resolve("fileSubSection.txt").apply { writeText("newContent") } + webClient.uploadFiles(listOf(changedFile)) + assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() + + val subV2 = submissionRepository.getExtByAccNo("S-RSTST1") + assertThat(subV2.version).isEqualTo(2) + assertThat(File("$submissionPath/${subV2.relPath}/Files/file section.doc")).exists() + assertThat(File("$submissionPath/${subV2.relPath}/Files/fileSubSection.txt")).hasContent("newContent") + assertThat(File("$submissionPath/${subV2.relPath}/Files/a/fileFileList.pdf")).exists() + } + + @Test + fun `5-2 resubmit existing submission with the same files`() = + runTest { + val submission = + tsv { + line("Submission", "S-RSTST2") + line("Title", "Simple Submission With Files 2") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + + line("Study") + line("Type", "Experiment") + line("File List", "file-list.tsv") + line() + + line("File", "file section.doc") + line("Type", "test") + line() + + line("Experiment", "Exp1") + line("Type", "Subsection") + line() + + line("File", "fileSubSection.txt") + line("Type", "Attached") + line() + }.toString() + + val fileListContent = + tsv { + line("Files", "Type") + line("a/fileFileList.pdf", "inner") + line("a", "folder") + }.toString() + + webClient.uploadFiles( + listOf( + tempFolder.createFile("fileSubSection.txt", "content"), + tempFolder.createFile("file-list.tsv", fileListContent), + tempFolder.createFile("file section.doc"), + ), + ) + webClient.uploadFiles(listOf(tempFolder.createFile("fileFileList.pdf")), "a") + assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() + + val sub = submissionRepository.getExtByAccNo("S-RSTST2") + assertThat(sub.version).isEqualTo(1) + assertThat(File("$submissionPath/${sub.relPath}/Files/file section.doc")).exists() + assertThat(File("$submissionPath/${sub.relPath}/Files/fileSubSection.txt")).exists() + assertThat(File("$submissionPath/${sub.relPath}/Files/fileSubSection.txt")).hasContent("content") + assertThat(File("$submissionPath/${sub.relPath}/Files/a/fileFileList.pdf")).exists() + + assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() + val subV2 = submissionRepository.getExtByAccNo("S-RSTST2") + assertThat(subV2.version).isEqualTo(2) + assertThat(File("$submissionPath/${subV2.relPath}/Files/file section.doc")).exists() + assertThat(File("$submissionPath/${subV2.relPath}/Files/fileSubSection.txt")).exists() + assertThat(File("$submissionPath/${subV2.relPath}/Files/fileSubSection.txt")).hasContent("content") + assertThat(File("$submissionPath/${subV2.relPath}/Files/a/fileFileList.pdf")).exists() + } + + @Test + fun `5-3 re submit a submission with rootPath`() { + val rootPath = "The-RootPath" + val dataFile = "DataFile1.txt" - val changedFile = tempFolder.resolve("fileSubSection.txt").apply { writeText("newContent") } - webClient.uploadFiles(listOf(changedFile)) - assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() - - val resubmitted = submissionRepository.getExtByAccNo("S-RSTST1") - assertThat(resubmitted.version).isEqualTo(2) - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/file section.doc")).exists() - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/fileSubSection.txt")).hasContent("newContent") - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/a/fileFileList.pdf")).exists() - } - - @Test - fun `5-2 resubmit existing submission with the same files`() = - runTest { val submission = tsv { - line("Submission", "S-RSTST2") - line("Title", "Simple Submission With Files 2") - line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line("Submission", "S-RSTST3") + line("Title", "Sample Submission") + line("RootPath", rootPath) line() - line("Study") - line("Type", "Experiment") - line("File List", "file-list.tsv") - line() - - line("File", "file section.doc") - line("Type", "test") - line() - - line("Experiment", "Exp1") - line("Type", "Subsection") line() - - line("File", "fileSubSection.txt") - line("Type", "Attached") + line("File", "DataFile1.txt") line() }.toString() - val fileListContent = - tsv { - line("Files", "Type") - line("a/fileFileList.pdf", "inner") - line("a", "folder") - }.toString() - - webClient.uploadFiles( - listOf( - tempFolder.createFile("fileSubSection.txt", "content"), - tempFolder.createFile("file-list.tsv", fileListContent), - tempFolder.createFile("file section.doc"), - ), - ) - webClient.uploadFiles(listOf(tempFolder.createFile("fileFileList.pdf")), "a") + webClient.uploadFiles(listOf(tempFolder.createFile("DataFile1.txt")), rootPath) assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() - val submitted = submissionRepository.getExtByAccNo("S-RSTST2") - assertThat(submitted.version).isEqualTo(1) - assertThat(File("$submissionPath/${submitted.relPath}/Files/file section.doc")).exists() - assertThat(File("$submissionPath/${submitted.relPath}/Files/fileSubSection.txt")).exists() - assertThat(File("$submissionPath/${submitted.relPath}/Files/fileSubSection.txt")).hasContent("content") - assertThat(File("$submissionPath/${submitted.relPath}/Files/a/fileFileList.pdf")).exists() + webClient.deleteFile(dataFile, rootPath) assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() - val resubmitted = submissionRepository.getExtByAccNo("S-RSTST2") - assertThat(resubmitted.version).isEqualTo(2) - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/file section.doc")).exists() - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/fileSubSection.txt")).exists() - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/fileSubSection.txt")).hasContent("content") - assertThat(File("$submissionPath/${resubmitted.relPath}/Files/a/fileFileList.pdf")).exists() } - - @Test - fun `5-3 re submit a submission with rootPath`() { - val rootPath = "The-RootPath" - val dataFile = "DataFile1.txt" - - val submission = - tsv { - line("Submission", "S-RSTST3") - line("Title", "Sample Submission") - line("RootPath", rootPath) - line() - line("Study") - line() - line("File", "DataFile1.txt") - line() - }.toString() - - webClient.uploadFiles(listOf(tempFolder.createFile("DataFile1.txt")), rootPath) - assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() - - webClient.deleteFile(dataFile, rootPath) - - assertThat(webClient.submitSingle(submission, TSV)).isSuccessful() } - @Test - fun `5-4 Make a public submission private should remove FTP files`() = - runTest { - val version1 = - tsv { - line("Submission", "S-RSTST5") - line("Title", "Public Submission") - line("ReleaseDate", OffsetDateTime.now().toStringDate()) - line() - line("Study") - line() - line("File", "file_5-5-1.txt") - line() - line("File", "file_5-5-2.txt") - line() - }.toString() - - webClient.uploadFile(tempFolder.createFile("file_5-5-1.txt", "5-5-1 file content")) - webClient.uploadFile(tempFolder.createFile("file_5-5-2.txt", "5-5-2 file content")) - assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() - - val subV1 = submissionRepository.getExtByAccNo("S-RSTST5") - val ftpFilesV1 = FileUtils.listAllFiles(File("$ftpPath/${subV1.relPath}/Files")) - val ftpFile1 = File("$ftpPath/${subV1.relPath}/Files/file_5-5-1.txt") - val ftpFile2 = File("$ftpPath/${subV1.relPath}/Files/file_5-5-2.txt") - - assertThat(ftpFilesV1).containsOnly(ftpFile1, ftpFile2) - assertThat(ftpFile1).hasContent("5-5-1 file content") - assertThat(ftpFile2).hasContent("5-5-2 file content") - assertThat(File("$submissionPath/${subV1.relPath}/Files/file_5-5-1.txt")).hasContent("5-5-1 file content") - assertThat(File("$submissionPath/${subV1.relPath}/Files/file_5-5-2.txt")).hasContent("5-5-2 file content") - - val version2 = - tsv { - line("Submission", "S-RSTST5") - line("Title", "Suppressed Submission") - line("ReleaseDate", "2050-05-22") - line() - line("Study") - line() - line("File", "file_5-5-1.txt") - line() - }.toString() - - assertThat(webClient.submitSingle(version2, TSV)).isSuccessful() - - val subV2 = submissionRepository.getExtByAccNo("S-RSTST5") - - assertThat(File("$ftpPath/${subV2.relPath}/Files")).isEmptyDirectory() - assertThat(File("$ftpPath/${subV2.relPath}/Files/file_5-5-1.txt")).doesNotExist() - assertThat(File("$ftpPath/${subV2.relPath}/Files/file_5-5-2.txt")).doesNotExist() - val submissionFilesV2 = FileUtils.listAllFiles(File("$submissionPath/${subV2.relPath}/Files")) - val expectedFileV2 = File("$submissionPath/${subV2.relPath}/Files/file_5-5-1.txt") - assertThat(submissionFilesV2).containsOnly(expectedFileV2) - assertThat(expectedFileV2).hasContent("5-5-1 file content") - } - - @Test - fun `5-6 add metadata to a public submission`() = - runTest { - val version1 = - tsv { - line("Submission", "S-RSTST6") - line("Title", "Simple submission to be updated") - line("ReleaseDate", OffsetDateTime.now().toStringDate()) - line() - line("Study") - line() - line("File", "5-6.txt") - line() - }.toString() - - webClient.uploadFiles(listOf(tempFolder.createFile("5-6.txt"))) - assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() - - mongoTemplate.updateMulti( - Query(where(SUB_ACC_NO).`in`("S-RSTST6").andOperator(where(SUB_VERSION).gt(0))), - ExtendedUpdate().set(SUB_RELEASE_TIME, OffsetDateTime.of(2018, 10, 10, 0, 0, 0, 0, UTC).toInstant()), - DocSubmission::class.java, - ).awaitSingleOrNull() + @Nested + inner class ModifyPublicMetadata { + @Test + fun `5-4 modify metadata of a public submission`() = + runTest { + val version1 = + tsv { + line("Submission", "S-RSTST4") + line("Title", "Public Submission") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line("Type", "Experiment") + line("File List", "file-list_5-4.tsv") + line() + line("File", "file_5-4-1.txt") + line() + line("File", "file_5-4-2.txt") + line() + }.toString() + + val fileListVersion1 = + tsv { + line("Files", "Type") + line("file_5-4-3.txt", "Referenced 1") + line("file_5-4-4.txt", "Referenced 2") + line() + }.toString() + + webClient.uploadFile(tempFolder.createFile("file-list_5-4.tsv", fileListVersion1)) + webClient.uploadFile(tempFolder.createFile("file_5-4-1.txt", "5-4-1 file content")) + webClient.uploadFile(tempFolder.createFile("file_5-4-2.txt", "5-4-2 file content")) + webClient.uploadFile(tempFolder.createFile("file_5-4-3.txt", "5-4-3 file content")) + webClient.uploadFile(tempFolder.createFile("file_5-4-4.txt", "5-4-4 file content")) + + assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() + + val version2 = + tsv { + line("Submission", "S-RSTST4") + line("Title", "Public Submission Updated") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line("Type", "Experiment Updated") + line("File List", "file-list_5-4.tsv") + line() + line("File", "file_5-4-1.txt") + line("Type", "Exp File 1") + line() + line("File", "file_5-4-2.txt") + line("Type", "Exp File 2") + line() + line("Link", "CHEBI::19") + line() + }.toString() + + val fileListVersion2 = + tsv { + line("Files", "Type") + line("file_5-4-3.txt", "Referenced And Updated 1") + line("file_5-4-4.txt", "Referenced And Updated 2") + line() + }.toString() + + webClient.uploadFile(tempFolder.createOrReplaceFile("file-list_5-4.tsv", fileListVersion2)) + assertThat(webClient.submitSingle(version2, TSV)).isSuccessful() + } + } - val version2 = - tsv { - line("Submission", "S-RSTST6") - line("Title", "Simple submission to be updated") - line("ReleaseDate", "2018-10-10") - line() - line("Study") - line("Type", "Exp") - line() - line("File", "5-6.txt") - line() - line("Link", "CHEBI::19") - line() - }.toString() - assertThat(webClient.submitSingle(version2, TSV)).isSuccessful() - } + @Nested + inner class ModifyPublicFiles { + @Test + fun `5-5 add files to public submission`() = + runTest { + val version1 = + tsv { + line("Submission", "S-RSTST5") + line("Title", "Add Submission Files") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line() + line("File", "file_5-5-1.txt") + line() + }.toString() + + webClient.uploadFile(tempFolder.createFile("file_5-5-1.txt", "5-5-1 file content")) + assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() + + val version2 = + tsv { + line("Submission", "S-RSTST5") + line("Title", "Update Submission Files") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line() + line("File", "file_5-5-1.txt") + line() + line("File", "file_5-5-2.txt") + line() + }.toString() + + webClient.uploadFile(tempFolder.createFile("file_5-5-2.txt", "5-5-2 file content")) + assertThat(webClient.submitSingle(version2, TSV)).isSuccessful() + } + + @Test + fun `5-6 unauthorized user updates public submission files`() = + runTest { + val version1 = + tsv { + line("Submission", "S-RSTST6") + line("Title", "Update Submission Files") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line("File List", "file-list_5-6.tsv") + line() + line("File", "file_5-6-1.txt") + line() + }.toString() + + val fileListVersion1 = + tsv { + line("Files", "Type") + line("file_5-6-2.txt", "Referenced") + line() + }.toString() + + webClient.uploadFile(tempFolder.createFile("file-list_5-6.tsv", fileListVersion1)) + webClient.uploadFile(tempFolder.createFile("file_5-6-1.txt", "5-6-1 file content")) + webClient.uploadFile(tempFolder.createFile("file_5-6-2.txt", "5-6-2 file content")) + assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() + + val version2 = + tsv { + line("Submission", "S-RSTST6") + line("Title", "Update Submission Files") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line("File List", "file-list_5-6.tsv") + line() + line("File", "file_5-6-1.txt") + line() + }.toString() + + webClient.uploadFile(tempFolder.createOrReplaceFile("file_5-6-1.txt", "5-6-1 file updated content")) + webClient.uploadFile(tempFolder.createOrReplaceFile("file_5-6-2.txt", "5-6-2 file updated content")) + webClient.submitAsync(version2, TSV) + + waitUntil(timeout = TWO_SECONDS) { requestRepository.getRequestStatus("S-RSTST6", 2) == INVALID } + } + + @Test + fun `5-7 authorized user updates public submission files`() = + runTest { + val version1 = + tsv { + line("Submission", "S-RSTST7") + line("Title", "Update Submission Files") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line() + line("File", "file_5-7-1.txt") + line() + line("File", "file_5-7-2.txt") + line() + }.toString() + + webClient.uploadFile(tempFolder.createFile("file_5-7-1.txt", "5-7-1 file content")) + webClient.uploadFile(tempFolder.createFile("file_5-7-2.txt", "5-7-2 file content")) + assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() + + val version2 = + tsv { + line("Submission", "S-RSTST7") + line("Title", "Update Submission Files") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line() + line("File", "file_5-7-1.txt") + line() + }.toString() + + webClient.grantPermission(SuperUser.email, "S-RSTST7", UPDATE_PUBLIC.name) + webClient.uploadFile(tempFolder.createOrReplaceFile("file_5-7-1.txt", "5-7-1 file updated content")) + + assertThat(webClient.submitSingle(version2, TSV)).isSuccessful() + } + + @Test + fun `5-8 unauthorized user removes file list`() = + runTest { + val version1 = + tsv { + line("Submission", "S-RSTST8") + line("Title", "Remove File List") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line("File List", "file-list_5-8.tsv") + line() + line("File", "file_5-8-1.txt") + line() + }.toString() + + val fileListVersion1 = + tsv { + line("Files", "Type") + line("file_5-8-2.txt", "Referenced") + line() + }.toString() + + webClient.uploadFile(tempFolder.createFile("file-list_5-8.tsv", fileListVersion1)) + webClient.uploadFile(tempFolder.createFile("file_5-8-1.txt", "5-8-1 file content")) + webClient.uploadFile(tempFolder.createFile("file_5-8-2.txt", "5-8-2 file content")) + assertThat(webClient.submitSingle(version1, TSV)).isSuccessful() + + val version2 = + tsv { + line("Submission", "S-RSTST8") + line("Title", "Remove File List") + line("ReleaseDate", OffsetDateTime.now().toStringDate()) + line() + line("Study") + line() + line("File", "file_5-8-1.txt") + line() + }.toString() + + webClient.submitAsync(version2, TSV) + + waitUntil(timeout = TWO_SECONDS) { requestRepository.getRequestStatus("S-RSTST8", 2) == INVALID } + } + } } diff --git a/submission/submission-webapp/src/itest/resources/itestsInventory/itestsInventory.md b/submission/submission-webapp/src/itest/resources/itestsInventory/itestsInventory.md index 17bf74f21..86b5bbbfa 100644 --- a/submission/submission-webapp/src/itest/resources/itestsInventory/itestsInventory.md +++ b/submission/submission-webapp/src/itest/resources/itestsInventory/itestsInventory.md @@ -31,10 +31,14 @@ | SubmitPermissionTest | 4-8 | owner resubmits without attach permission | | | SubmitPermissionTest | 4-9 | not owner user resubmits without the update permission | | | SubmitPermissionTest | 4-10 | not owner user resubmits with the update permission | | -| ResubmissionApiTest | 5-1 | resubmit existing submission | Shows the system behaves when resubmissions occurs | +| ResubmissionApiTest | 5-1 | resubmit private existing submission | Shows the system behaves when resubmissions occurs | | ResubmissionApiTest | 5-2 | resubmit existing submission with the same files | | | ResubmissionApiTest | 5-3 | re submit a submission with rootPath | | -| ResubmissionApiTest | 5-4 | Make a public submission private should remove FTP files | | +| ResubmissionApiTest | 5-4 | modify metadata of a public submission | | +| ResubmissionApiTest | 5-5 | add files to public submission | | +| ResubmissionApiTest | 5-6 | unauthorized user updates public submission files | | +| ResubmissionApiTest | 5-7 | authorized user updates public submission files | | +| ResubmissionApiTest | 5-8 | unauthorized user removes file list | | | SubmissionFileSourceTest | 6-1 | resubmission with SUBMISSION file source as priority over USER_SPACE | Considers submission with different source files, user space, fire, bypassing files with fire | | SubmissionFileSourceTest | 6-3-1 | submission with directory with files on FIRE | | | SubmissionFileSourceTest | 6-3-2-1 | re-submission with directory with files on FIRE | | @@ -169,4 +173,4 @@ | SubmissionDatesTest | 28-5 | Regular user re-submit a private submission with a new release date in the past | | | SubmissionDatesTest | 28-6 | Admin submit and re Submit in the past | | | SubmissionDatesTest | 28-7 | Admin make a public submission private | | -| SubmissionDatesTest | 28-8 | Admin make a Regular user public submission private | | +| SubmissionDatesTest | 28-8 | Admin make a Regular user public submission private | | diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionWebConfig.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionWebConfig.kt index 9e502286c..50dd8c710 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionWebConfig.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/common/config/SubmissionWebConfig.kt @@ -21,6 +21,7 @@ import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestLoader import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestProcessor import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestReleaser import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestSaver +import ac.uk.ebi.biostd.submission.domain.request.SubmissionRequestValidator import ac.uk.ebi.biostd.submission.domain.service.SubmissionDraftService import ac.uk.ebi.biostd.submission.domain.service.SubmissionRequestService import ac.uk.ebi.biostd.submission.domain.submission.SubmissionQueryService @@ -55,8 +56,9 @@ class SubmissionWebConfig { persistenceService: SubmissionPersistenceService, queryService: SubmissionPersistenceQueryService, requestIndexer: SubmissionRequestIndexer, - requestCleanIndexer: SubmissionRequestCleanIndexer, requestLoader: SubmissionRequestLoader, + requestCleanIndexer: SubmissionRequestCleanIndexer, + requestValidator: SubmissionRequestValidator, requestProcessor: SubmissionRequestProcessor, submissionReleaser: SubmissionRequestReleaser, submissionCleaner: SubmissionRequestCleaner, @@ -70,8 +72,9 @@ class SubmissionWebConfig { requestService, persistenceService, requestIndexer, - requestCleanIndexer, requestLoader, + requestCleanIndexer, + requestValidator, requestProcessor, submissionReleaser, submissionCleaner, diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/files/service/ftp/FtpFileService.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/files/service/ftp/FtpFileService.kt index 263ddd385..8b31cc7c9 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/files/service/ftp/FtpFileService.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/files/service/ftp/FtpFileService.kt @@ -34,7 +34,7 @@ class FtpFileService( path: String, fileName: String, ): File { - val target = Files.createTempFile(path, fileName) + val target = Files.createTempFile(null, fileName) val ftpPath = basePath.resolve(path).resolve(fileName) target.outputStream().use { ftp.downloadFile(ftpPath, it) } diff --git a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionMessageListener.kt b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionMessageListener.kt index ac9fcdec3..2acf78efe 100644 --- a/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionMessageListener.kt +++ b/submission/submission-webapp/src/main/kotlin/ac/uk/ebi/biostd/submission/domain/service/SubmissionMessageListener.kt @@ -13,6 +13,7 @@ import ebi.ac.uk.extended.events.RequestLoaded import ebi.ac.uk.extended.events.RequestMessage import ebi.ac.uk.extended.events.RequestPersisted import ebi.ac.uk.extended.events.RequestToCleanIndexed +import ebi.ac.uk.extended.events.RequestValidated import kotlinx.coroutines.runBlocking import mu.KotlinLogging import org.springframework.amqp.rabbit.annotation.RabbitHandler @@ -56,7 +57,16 @@ class SubmissionMessageListener( } @RabbitHandler - fun cleanRequest(rqt: RequestToCleanIndexed) { + fun validate(rqt: RequestToCleanIndexed) { + processSafely(rqt) { + val (accNo, version) = rqt + logger.info { "$accNo, Received validation message for submission $accNo, version: $version" } + submissionSubmitter.validateRequest(accNo, version) + } + } + + @RabbitHandler + fun cleanRequest(rqt: RequestValidated) { processSafely(rqt) { val (accNo, version) = rqt logger.info { "$accNo, Received clean message for submission $accNo, version: $version" } diff --git a/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/resolvers/TestUserPathResolver.kt b/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/resolvers/TestUserPathResolver.kt deleted file mode 100644 index 42de6c723..000000000 --- a/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/resolvers/TestUserPathResolver.kt +++ /dev/null @@ -1,21 +0,0 @@ -package ac.uk.ebi.biostd.resolvers - -import ac.uk.ebi.biostd.files.web.common.UserPath -import org.springframework.core.MethodParameter -import org.springframework.web.bind.support.WebDataBinderFactory -import org.springframework.web.context.request.NativeWebRequest -import org.springframework.web.method.support.HandlerMethodArgumentResolver -import org.springframework.web.method.support.ModelAndViewContainer - -internal const val TEST_USER_PATH = "/test/path" - -internal class TestUserPathResolver : HandlerMethodArgumentResolver { - override fun supportsParameter(parameter: MethodParameter) = parameter.parameterType == UserPath::class.java - - override fun resolveArgument( - parameter: MethodParameter, - mavContainer: ModelAndViewContainer, - webRequest: NativeWebRequest, - binderFactory: WebDataBinderFactory, - ) = UserPath(TEST_USER_PATH) -} diff --git a/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/stats/web/mapping/StatsMapperTest.kt b/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/stats/web/mapping/StatsMapperTest.kt index 596d40973..9deedc7d4 100644 --- a/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/stats/web/mapping/StatsMapperTest.kt +++ b/submission/submission-webapp/src/test/kotlin/ac/uk/ebi/biostd/stats/web/mapping/StatsMapperTest.kt @@ -15,7 +15,7 @@ class StatsMapperTest { val stat = SingleSubmissionStat("S-BSST0", 12L, FILES_SIZE) val expectedDto = SubmissionStat("S-BSST0", 12L, FILES_SIZE.value) - assertThat(stat.toStatDto()).isEqualToComparingFieldByField(expectedDto) + assertThat(stat.toStatDto()).usingRecursiveComparison().isEqualTo(expectedDto) } @Test @@ -23,7 +23,7 @@ class StatsMapperTest { val dto = SubmissionStat("S-BSST0", 12L, "FILES_SIZE") val expectedStat = SingleSubmissionStat("S-BSST0", 12L, FILES_SIZE) - assertThat(dto.toStat()).isEqualToComparingFieldByField(expectedStat) + assertThat(dto.toStat()).usingRecursiveComparison().isEqualTo(expectedStat) } @Test