diff --git a/pom.xml b/pom.xml
index e499214be..18d2c84fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
bio.overture
song
pom
- 3.0.1
+ 3.1.0
song-core
song-java-sdk
diff --git a/song-client/pom.xml b/song-client/pom.xml
index 0b7b6b442..fdd96a774 100644
--- a/song-client/pom.xml
+++ b/song-client/pom.xml
@@ -18,7 +18,7 @@
song
bio.overture
- 3.0.1
+ 3.1.0
4.0.0
@@ -35,12 +35,12 @@
bio.overture
song-java-sdk
- 3.0.1
+ 3.1.0
bio.overture
song-core
- 3.0.1
+ 3.1.0
diff --git a/song-core/pom.xml b/song-core/pom.xml
index b3f299d96..14fe5f6f3 100644
--- a/song-core/pom.xml
+++ b/song-core/pom.xml
@@ -19,7 +19,7 @@
song
bio.overture
- 3.0.1
+ 3.1.0
4.0.0
diff --git a/song-core/src/main/java/bio/overture/song/core/model/FileUpdateResponse.java b/song-core/src/main/java/bio/overture/song/core/model/FileUpdateResponse.java
index 098224428..f2177e2b9 100644
--- a/song-core/src/main/java/bio/overture/song/core/model/FileUpdateResponse.java
+++ b/song-core/src/main/java/bio/overture/song/core/model/FileUpdateResponse.java
@@ -30,8 +30,8 @@
@AllArgsConstructor
public class FileUpdateResponse {
private FileUpdateTypes fileUpdateType;
- private AnalysisStates originalAnalysisState;
- private boolean unpublishedAnalysis;
+ @Deprecated private AnalysisStates originalAnalysisState;
+ @Deprecated private boolean unpublishedAnalysis;
private String message;
private FileDTO originalFile;
}
diff --git a/song-java-sdk/pom.xml b/song-java-sdk/pom.xml
index a11202050..4b0250c72 100644
--- a/song-java-sdk/pom.xml
+++ b/song-java-sdk/pom.xml
@@ -18,7 +18,7 @@
song
bio.overture
- 3.0.1
+ 3.1.0
4.0.0
diff --git a/song-server/pom.xml b/song-server/pom.xml
index 1cda9e6c7..04c99d2b9 100644
--- a/song-server/pom.xml
+++ b/song-server/pom.xml
@@ -19,7 +19,7 @@
song
bio.overture
- 3.0.1
+ 3.1.0
4.0.0
@@ -37,7 +37,7 @@
bio.overture
song-core
- 3.0.1
+ 3.1.0
diff --git a/song-server/src/main/java/bio/overture/song/server/controller/StudyController.java b/song-server/src/main/java/bio/overture/song/server/controller/StudyController.java
index 42eb90e15..671a29d3d 100644
--- a/song-server/src/main/java/bio/overture/song/server/controller/StudyController.java
+++ b/song-server/src/main/java/bio/overture/song/server/controller/StudyController.java
@@ -22,6 +22,7 @@
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+import bio.overture.song.server.model.dto.GenericMessage;
import bio.overture.song.server.model.entity.Study;
import bio.overture.song.server.model.entity.composites.StudyWithDonors;
import bio.overture.song.server.service.StudyService;
@@ -78,7 +79,7 @@ public List findAllStudies() {
consumes = {APPLICATION_JSON_VALUE, APPLICATION_JSON_UTF8_VALUE})
@PreAuthorize("@studySecurity.authorize(authentication, #studyId)")
@ResponseBody
- public String saveStudy(
+ public GenericMessage saveStudy(
@PathVariable("studyId") String studyId,
@RequestHeader(value = AUTHORIZATION, required = false) final String accessToken,
@RequestBody Study study) {
@@ -89,6 +90,6 @@ public String saveStudy(
"The studyId in the URL '%s' should match the studyId '%s' in the payload",
studyId,
study.getStudyId());
- return studyService.saveStudy(study);
+ return new GenericMessage(studyService.saveStudy(study));
}
}
diff --git a/song-server/src/main/java/bio/overture/song/server/model/dto/GenericMessage.java b/song-server/src/main/java/bio/overture/song/server/model/dto/GenericMessage.java
new file mode 100644
index 000000000..bdc692ab1
--- /dev/null
+++ b/song-server/src/main/java/bio/overture/song/server/model/dto/GenericMessage.java
@@ -0,0 +1,9 @@
+package bio.overture.song.server.model.dto;
+
+import lombok.NonNull;
+import lombok.Value;
+
+@Value
+public class GenericMessage {
+ @NonNull private final String message;
+}
diff --git a/song-server/src/main/java/bio/overture/song/server/model/entity/Donor.java b/song-server/src/main/java/bio/overture/song/server/model/entity/Donor.java
index e94ad4f5e..16f02d003 100644
--- a/song-server/src/main/java/bio/overture/song/server/model/entity/Donor.java
+++ b/song-server/src/main/java/bio/overture/song/server/model/entity/Donor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018. Ontario Institute for Cancer Research
+ * Copyright (c) 2018 - 2019. Ontario Institute for Cancer Research
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,8 +17,6 @@
package bio.overture.song.server.model.entity;
-import static bio.overture.song.server.model.enums.Constants.DONOR_GENDER;
-import static bio.overture.song.server.model.enums.Constants.validate;
import static bio.overture.song.server.model.enums.TableNames.DONOR;
import bio.overture.song.core.model.Metadata;
@@ -30,18 +28,20 @@
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
+import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Table(name = DONOR)
@Data
@Builder
-@RequiredArgsConstructor
+@NoArgsConstructor
+@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@JsonPropertyOrder({
@@ -68,23 +68,6 @@ public class Donor extends Metadata {
@Column(name = TableAttributeNames.GENDER, nullable = true)
private String donorGender;
- // NOTE: Since the donorGender field is validated upon setting it, using Lomboks default Builder
- // when
- // the @AllArgsConstructor is used will by pass the validation since the Builder uses the All Arg
- // Constructor.
- // By using the setter inside the constructor, the building of a Donor will always be validated
- public Donor(String donorId, String studyId, String donorSubmitterId, String donorGender) {
- this.donorId = donorId;
- this.studyId = studyId;
- this.donorSubmitterId = donorSubmitterId;
- setDonorGender(donorGender);
- }
-
- public void setDonorGender(String gender) {
- validate(DONOR_GENDER, gender);
- this.donorGender = gender;
- }
-
public void setWithDonor(@NonNull Donor donorUpdate) {
setDonorSubmitterId(donorUpdate.getDonorSubmitterId());
setDonorGender(donorUpdate.getDonorGender());
diff --git a/song-server/src/main/java/bio/overture/song/server/model/entity/FileEntity.java b/song-server/src/main/java/bio/overture/song/server/model/entity/FileEntity.java
index dbefa903f..778cd1032 100644
--- a/song-server/src/main/java/bio/overture/song/server/model/entity/FileEntity.java
+++ b/song-server/src/main/java/bio/overture/song/server/model/entity/FileEntity.java
@@ -17,8 +17,6 @@
package bio.overture.song.server.model.entity;
-import static bio.overture.song.core.model.enums.AccessTypes.resolveAccessType;
-
import bio.overture.song.core.model.File;
import bio.overture.song.core.model.FileData;
import bio.overture.song.core.model.Metadata;
@@ -32,18 +30,20 @@
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
+import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Table(name = TableNames.FILE)
@Data
@Builder
-@RequiredArgsConstructor
+@NoArgsConstructor
+@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@@ -74,38 +74,19 @@ public class FileEntity extends Metadata implements Serializable, FileData, File
@Column(name = TableAttributeNames.ACCESS, nullable = false)
private String fileAccess;
- public FileEntity(
- String objectId,
- String studyId,
- String analysisId,
- String fileName,
- Long fileSize,
- String fileType,
- String fileMd5sum,
- String fileAccess) {
- this.objectId = objectId;
- this.studyId = studyId;
- this.analysisId = analysisId;
- this.fileName = fileName;
- this.fileSize = fileSize;
- setFileType(fileType);
- this.fileMd5sum = fileMd5sum;
- setFileAccess(fileAccess);
+ public void setFileType(@NonNull String fileType) {
+ this.fileType = fileType;
}
- public void setFileType(FileTypes type) {
+ public void setFileType(@NonNull FileTypes type) {
this.fileType = type.toString();
}
- public void setFileType(String type) {
- setFileType(FileTypes.resolveFileType(type));
+ public void setFileAccess(@NonNull String fileAccess) {
+ this.fileAccess = fileAccess;
}
public void setFileAccess(@NonNull AccessTypes access) {
this.fileAccess = access.toString();
}
-
- public void setFileAccess(@NonNull String access) {
- setFileAccess(resolveAccessType(access));
- }
}
diff --git a/song-server/src/main/java/bio/overture/song/server/model/entity/Sample.java b/song-server/src/main/java/bio/overture/song/server/model/entity/Sample.java
index cd341a1b3..59dd6e378 100644
--- a/song-server/src/main/java/bio/overture/song/server/model/entity/Sample.java
+++ b/song-server/src/main/java/bio/overture/song/server/model/entity/Sample.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018. Ontario Institute for Cancer Research
+ * Copyright (c) 2018 - 2019. Ontario Institute for Cancer Research
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,9 +17,6 @@
package bio.overture.song.server.model.entity;
-import static bio.overture.song.server.model.enums.Constants.SAMPLE_TYPE;
-import static bio.overture.song.server.model.enums.Constants.validate;
-
import bio.overture.song.core.model.Metadata;
import bio.overture.song.server.model.enums.TableAttributeNames;
import bio.overture.song.server.model.enums.TableNames;
@@ -28,18 +25,20 @@
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
+import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Table(name = TableNames.SAMPLE)
@Data
@Builder
-@RequiredArgsConstructor
+@NoArgsConstructor
+@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.ALWAYS)
@@ -58,18 +57,6 @@ public class Sample extends Metadata {
@Column(name = TableAttributeNames.TYPE, nullable = false)
private String sampleType;
- public Sample(String sampleId, String specimenId, String sampleSubmitterId, String sampleType) {
- this.sampleId = sampleId;
- this.specimenId = specimenId;
- this.sampleSubmitterId = sampleSubmitterId;
- setSampleType(sampleType);
- }
-
- public void setSampleType(String type) {
- validate(SAMPLE_TYPE, type);
- sampleType = type;
- }
-
public void setWithSample(@NonNull Sample u) {
setSampleId(u.getSampleId());
setSampleSubmitterId(u.getSampleSubmitterId());
diff --git a/song-server/src/main/java/bio/overture/song/server/model/entity/Specimen.java b/song-server/src/main/java/bio/overture/song/server/model/entity/Specimen.java
index 9244dc1a0..9ef163b81 100644
--- a/song-server/src/main/java/bio/overture/song/server/model/entity/Specimen.java
+++ b/song-server/src/main/java/bio/overture/song/server/model/entity/Specimen.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018. Ontario Institute for Cancer Research
+ * Copyright (c) 2018-2019. Ontario Institute for Cancer Research
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -17,10 +17,6 @@
package bio.overture.song.server.model.entity;
-import static bio.overture.song.server.model.enums.Constants.SPECIMEN_CLASS;
-import static bio.overture.song.server.model.enums.Constants.SPECIMEN_TYPE;
-import static bio.overture.song.server.model.enums.Constants.validate;
-
import bio.overture.song.core.model.Metadata;
import bio.overture.song.server.model.enums.TableAttributeNames;
import bio.overture.song.server.model.enums.TableNames;
@@ -29,18 +25,20 @@
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
+import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Table(name = TableNames.SPECIMEN)
@Data
@Builder
-@RequiredArgsConstructor
+@NoArgsConstructor
+@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_ABSENT)
@@ -62,29 +60,6 @@ public class Specimen extends Metadata {
@Column(name = TableAttributeNames.TYPE, nullable = false)
private String specimenType;
- public Specimen(
- String specimenId,
- String donorId,
- String specimenSubmitterId,
- String specimenClass,
- String specimenType) {
- this.specimenId = specimenId;
- this.donorId = donorId;
- this.specimenSubmitterId = specimenSubmitterId;
- setSpecimenClass(specimenClass);
- setSpecimenType(specimenType);
- }
-
- public void setSpecimenClass(String specimenClass) {
- validate(SPECIMEN_CLASS, specimenClass);
- this.specimenClass = specimenClass;
- }
-
- public void setSpecimenType(String type) {
- validate(SPECIMEN_TYPE, type);
- specimenType = type;
- }
-
public void setWithSpecimen(@NonNull Specimen specimenUpdate) {
setSpecimenSubmitterId(specimenUpdate.getSpecimenSubmitterId());
setDonorId(specimenUpdate.getDonorId());
diff --git a/song-server/src/main/java/bio/overture/song/server/properties/IdProperties.java b/song-server/src/main/java/bio/overture/song/server/properties/IdProperties.java
index d0dca7832..2af1e9d3c 100644
--- a/song-server/src/main/java/bio/overture/song/server/properties/IdProperties.java
+++ b/song-server/src/main/java/bio/overture/song/server/properties/IdProperties.java
@@ -32,7 +32,6 @@ public static class UriTemplateProperties {
private String donor;
private String specimen;
private String sample;
- private String file;
}
@Getter
diff --git a/song-server/src/main/java/bio/overture/song/server/service/FileModificationService.java b/song-server/src/main/java/bio/overture/song/server/service/FileModificationService.java
index 7d860c3a9..cfd2e0fba 100644
--- a/song-server/src/main/java/bio/overture/song/server/service/FileModificationService.java
+++ b/song-server/src/main/java/bio/overture/song/server/service/FileModificationService.java
@@ -21,7 +21,6 @@
import static bio.overture.song.core.exceptions.ServerErrors.INVALID_FILE_UPDATE_REQUEST;
import static bio.overture.song.core.exceptions.ServerException.buildServerException;
import static bio.overture.song.core.exceptions.ServerException.checkServer;
-import static bio.overture.song.core.model.enums.AnalysisStates.PUBLISHED;
import static bio.overture.song.core.model.enums.AnalysisStates.SUPPRESSED;
import static bio.overture.song.core.model.enums.AnalysisStates.UNPUBLISHED;
import static bio.overture.song.core.model.enums.FileUpdateTypes.CONTENT_UPDATE;
@@ -64,9 +63,33 @@ public FileModificationService(
@Transactional
public FileUpdateTypes updateWithRequest(
@NonNull FileEntity originalFile, FileData fileUpdateRequest) {
- val updatedFile = createUpdateFile(originalFile, fileUpdateRequest);
- fileService.unsafeUpdate(updatedFile);
- return resolveFileUpdateType(originalFile, fileUpdateRequest);
+ val analysisId = originalFile.getAnalysisId();
+ val objectId = originalFile.getObjectId();
+ val currentState = analysisService.readState(analysisId);
+ val fileUpdateType = resolveFileUpdateType(originalFile, fileUpdateRequest);
+
+ boolean doUpdate = false;
+ if (fileUpdateType == METADATA_UPDATE) {
+ doUpdate = true;
+ } else if (fileUpdateType == CONTENT_UPDATE) {
+ checkServer(
+ currentState == UNPUBLISHED,
+ getClass(),
+ ILLEGAL_FILE_UPDATE_REQUEST,
+ "The file with objectId '%s' and analysisId '%s' cannot be updated since its analysisState is '%s' and '%s' is required",
+ objectId,
+ analysisId,
+ currentState,
+ UNPUBLISHED);
+ doUpdate = true;
+ }
+
+ if (doUpdate) {
+ val updatedFile = createUpdateFile(originalFile, fileUpdateRequest);
+ fileService.unsafeUpdate(updatedFile);
+ }
+
+ return fileUpdateType;
}
/**
@@ -100,39 +123,27 @@ public FileUpdateResponse securedFileWithAnalysisUpdate(
+ "be updated since its analysisState is '%s'",
objectId,
analysisId,
- SUPPRESSED.toString());
+ currentState.toString());
// Update the target file record using the originalFile and the update request
val fileUpdateType = updateWithRequest(originalFile, fileUpdateRequest);
-
- // Build the response
val response = FileUpdateResponse.builder().unpublishedAnalysis(false);
+ if (fileUpdateType == METADATA_UPDATE || fileUpdateType == CONTENT_UPDATE) {
+ response.message(
+ format("Updated file with objectId '%s' and analysisId '%s'", objectId, analysisId));
+ } else if (fileUpdateType == NO_UPDATE) {
+ response.message(
+ format(
+ "No update for file with objectId '%s' and analysisId '%s'", objectId, analysisId));
+ } else {
+ throw new IllegalStateException("Could not process fileUpdateType: " + fileUpdateType);
+ }
+ // Build the response
+
response.originalFile(fileConverter.convertToFileDTO(originalFile));
response.originalAnalysisState(currentState);
response.fileUpdateType(fileUpdateType);
- // Can only transition from PUBLISHED to UNPUBLISHED states.
- if (currentState == PUBLISHED) {
- if (doUnpublish(fileUpdateType)) {
- analysisService.securedUpdateState(studyId, analysisId, UNPUBLISHED);
- response.unpublishedAnalysis(true);
- response.message(
- format(
- "[WARNING]: Changed analysis from '%s' to '%s'",
- PUBLISHED.toString(), UNPUBLISHED.toString()));
- } else {
- response.message(
- format(
- "Original analysisState '%s' was not changed since the fileUpdateType was '%s'",
- currentState.toString(), fileUpdateType.name()));
- }
- } else if (currentState == UNPUBLISHED) { // Can still update an unpublished analysis
- response.message(
- format("Did not change analysisState since it is '%s'", currentState.toString()));
- } else {
- throw new IllegalStateException(
- format("Could not process the analysisState '%s'", currentState.toString()));
- }
return response.build();
}
@@ -159,21 +170,4 @@ private FileEntity createUpdateFile(
fileConverter.updateEntityFromData(fileUpdateData, updatedFile);
return updatedFile;
}
-
- /**
- * Decides whether or not the input {@code fileUpdateType} should unpublish an analysis
- *
- * @param fileUpdateType
- * @return boolean
- */
- public static boolean doUnpublish(@NonNull FileUpdateTypes fileUpdateType) {
- if (fileUpdateType == CONTENT_UPDATE) {
- return true;
- } else if (fileUpdateType == METADATA_UPDATE || fileUpdateType == NO_UPDATE) {
- return false;
- } else {
- throw new IllegalStateException(
- format("The updateType '%s' is unrecognized", fileUpdateType.name()));
- }
- }
}
diff --git a/song-server/src/main/java/bio/overture/song/server/service/FileService.java b/song-server/src/main/java/bio/overture/song/server/service/FileService.java
index 37051c08c..5f19d330a 100644
--- a/song-server/src/main/java/bio/overture/song/server/service/FileService.java
+++ b/song-server/src/main/java/bio/overture/song/server/service/FileService.java
@@ -58,7 +58,7 @@ public String create(
result,
getClass(),
ID_NOT_FOUND,
- "The fileId for analysisId '%s' and fileName '%s' was not found",
+ "The objectId for analysisId '%s' and fileName '%s' was not found",
analysisId,
file.getFileName());
diff --git a/song-server/src/main/java/bio/overture/song/server/service/StudyService.java b/song-server/src/main/java/bio/overture/song/server/service/StudyService.java
index fc00b4ea7..da49d52c0 100644
--- a/song-server/src/main/java/bio/overture/song/server/service/StudyService.java
+++ b/song-server/src/main/java/bio/overture/song/server/service/StudyService.java
@@ -19,6 +19,7 @@
import static bio.overture.song.core.exceptions.ServerErrors.STUDY_ALREADY_EXISTS;
import static bio.overture.song.core.exceptions.ServerErrors.STUDY_ID_DOES_NOT_EXIST;
import static bio.overture.song.core.exceptions.ServerException.checkServer;
+import static java.lang.String.format;
import static java.lang.Thread.currentThread;
import static org.icgc.dcc.common.core.util.stream.Collectors.toImmutableList;
@@ -72,7 +73,7 @@ public String saveStudy(Study study) {
study);
studyRepository.save(study);
infoService.create(id, study.getInfoAsString());
- return id;
+ return format("Successfully created study '%s'", id);
}
public List findAllStudies() {
diff --git a/song-server/src/main/java/bio/overture/song/server/service/UploadService.java b/song-server/src/main/java/bio/overture/song/server/service/UploadService.java
index 226de1442..c396c8d28 100644
--- a/song-server/src/main/java/bio/overture/song/server/service/UploadService.java
+++ b/song-server/src/main/java/bio/overture/song/server/service/UploadService.java
@@ -16,6 +16,21 @@
*/
package bio.overture.song.server.service;
+import bio.overture.song.core.model.AnalysisTypeId;
+import bio.overture.song.core.model.SubmitResponse;
+import bio.overture.song.server.model.dto.Payload;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.NonNull;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.io.IOException;
+
+import static java.util.Objects.isNull;
import static bio.overture.song.core.exceptions.ServerErrors.ANALYSIS_TYPE_INCORRECT_VERSION;
import static bio.overture.song.core.exceptions.ServerErrors.MALFORMED_PARAMETER;
import static bio.overture.song.core.exceptions.ServerErrors.PAYLOAD_PARSING;
@@ -27,20 +42,9 @@
import static bio.overture.song.core.utils.JsonUtils.fromJson;
import static bio.overture.song.core.utils.JsonUtils.readTree;
import static bio.overture.song.core.utils.Responses.OK;
+import static bio.overture.song.server.model.enums.ModelAttributeNames.ANALYSIS_TYPE;
+import static bio.overture.song.server.model.enums.ModelAttributeNames.NAME;
import static bio.overture.song.server.model.enums.ModelAttributeNames.STUDY;
-import static java.util.Objects.isNull;
-
-import bio.overture.song.core.model.SubmitResponse;
-import bio.overture.song.server.model.dto.Payload;
-import com.fasterxml.jackson.databind.JsonNode;
-import java.io.IOException;
-import javax.transaction.Transactional;
-import lombok.NonNull;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
@Service
@Slf4j
@@ -82,22 +86,11 @@ public SubmitResponse submit(@NonNull String studyId, String payloadString) {
return SubmitResponse.builder().analysisId(analysisId).status(OK).build();
}
- private void checkAnalysisTypeVersion(@NonNull Payload payload) {
- checkServer(
- !isNull(payload.getAnalysisType()),
- getClass(),
- MALFORMED_PARAMETER,
- "The analysisType field cannot be null");
- val analysisTypeId = payload.getAnalysisType();
- val errors = validator.validateAnalysisTypeVersion(analysisTypeId);
- checkServer(isNull(errors), getClass(), ANALYSIS_TYPE_INCORRECT_VERSION, errors);
- }
-
private JsonNode parsePayload(String payloadString) {
try {
val payloadJson = readTree(payloadString);
- val payload = fromJson(payloadJson, Payload.class);
- checkAnalysisTypeVersion(payload);
+ val analysisTypeId = parseAnalysisTypeId(payloadJson);
+ checkAnalysisTypeVersion(analysisTypeId);
return payloadJson;
} catch (IOException e) {
log.error(e.getMessage());
@@ -108,6 +101,18 @@ private JsonNode parsePayload(String payloadString) {
}
}
+ private void checkAnalysisTypeVersion(@NonNull AnalysisTypeId analysisTypeId) {
+ val errors = validator.validateAnalysisTypeVersion(analysisTypeId);
+ checkServer(isNull(errors), getClass(), ANALYSIS_TYPE_INCORRECT_VERSION, errors);
+ }
+
+ private AnalysisTypeId parseAnalysisTypeId(@NonNull JsonNode payloadJson){
+ checkServer(payloadJson.has(ANALYSIS_TYPE), getClass(), MALFORMED_PARAMETER, "The analysisType field cannot be null");
+ val analysisTypePath = payloadJson.path(ANALYSIS_TYPE);
+ checkServer(analysisTypePath.has(NAME), getClass(), MALFORMED_PARAMETER, "The analysisType name field cannot be null");
+ return fromJson(analysisTypePath, AnalysisTypeId.class);
+ }
+
private void validatePayload(JsonNode payloadJson) {
// Validate payload format and content
val error = validator.validate(payloadJson);
diff --git a/song-server/src/main/java/bio/overture/song/server/service/id/FederatedIdService.java b/song-server/src/main/java/bio/overture/song/server/service/id/FederatedIdService.java
index f2ce160e1..e1457ad00 100644
--- a/song-server/src/main/java/bio/overture/song/server/service/id/FederatedIdService.java
+++ b/song-server/src/main/java/bio/overture/song/server/service/id/FederatedIdService.java
@@ -20,12 +20,6 @@ public class FederatedIdService implements IdService {
@NonNull private final IdService localIdService;
@NonNull private final UriResolver uriResolver;
- @Override
- public Optional getFileId(@NonNull String analysisId, @NonNull String fileName) {
- return handleIdServiceGetRequest(
- uriResolver.expandFileUri(analysisId, fileName), rest::getString);
- }
-
@Override
public Optional getDonorId(@NonNull String studyId, @NonNull String submitterDonorId) {
return handleIdServiceGetRequest(
@@ -45,13 +39,20 @@ public Optional getSampleId(@NonNull String studyId, @NonNull String sub
uriResolver.expandSampleUri(studyId, submitterSampleId), rest::getString);
}
+ /** Always generate the analysisId locally */
@Override
public String generateAnalysisId() {
return localIdService.generateAnalysisId();
}
+ // Always generate the objectId locally
+ @Override
+ public Optional getFileId(@NonNull String analysisId, @NonNull String fileName) {
+ return localIdService.getFileId(analysisId, fileName);
+ }
+
/**
- * This method calls the callback function with the input url, and if successfull (1xx/2xx/3xx
+ * This method calls the callback function with the input url, and if successful (1xx/2xx/3xx
* status code) returns the result, otherwise throws a ServerException
*/
private static T handleIdServiceGetRequest(String url, Function restCallback) {
diff --git a/song-server/src/main/java/bio/overture/song/server/service/id/UriResolver.java b/song-server/src/main/java/bio/overture/song/server/service/id/UriResolver.java
index 3b6d9ceac..9c88042c3 100644
--- a/song-server/src/main/java/bio/overture/song/server/service/id/UriResolver.java
+++ b/song-server/src/main/java/bio/overture/song/server/service/id/UriResolver.java
@@ -30,16 +30,11 @@ public class UriResolver {
private static final String STUDY_ID = "studyId";
/** Dependencies */
- @NonNull private final UriTemplate fileUriTemplate;
-
@NonNull private final UriTemplate donorUriTemplate;
+
@NonNull private final UriTemplate specimenUriTemplate;
@NonNull private final UriTemplate sampleUriTemplate;
- public String expandFileUri(@NonNull String analysisId, @NonNull String fileName) {
- return fileUriTemplate.expand(Map.of(ANALYSIS_ID, analysisId, FILE_NAME, fileName)).toString();
- }
-
public String expandDonorUri(@NonNull String studyId, @NonNull String submitterId) {
return donorUriTemplate.expand(Map.of(STUDY_ID, studyId, SUBMITTER_ID, submitterId)).toString();
}
@@ -60,7 +55,6 @@ public String expandSampleUri(@NonNull String studyId, @NonNull String submitter
public static UriResolver createUriResolver(
@NonNull UriTemplateProperties uriTemplateProperties) {
return UriResolver.builder()
- .fileUriTemplate(processTemplate(uriTemplateProperties.getFile(), ANALYSIS_ID, FILE_NAME))
.donorUriTemplate(processTemplate(uriTemplateProperties.getDonor(), STUDY_ID, SUBMITTER_ID))
.specimenUriTemplate(
processTemplate(uriTemplateProperties.getSpecimen(), STUDY_ID, SUBMITTER_ID))
diff --git a/song-server/src/main/resources/application.yml b/song-server/src/main/resources/application.yml
index 6d40dc4ed..fbffbe3ac 100644
--- a/song-server/src/main/resources/application.yml
+++ b/song-server/src/main/resources/application.yml
@@ -88,7 +88,6 @@ id:
donor: https://id.example.org/donor/id?submittedProjectId={studyId}&submittedDonorId={submitterId}&create=true
specimen: https://id.example.org/specimen/id?submittedProjectId={studyId}&submittedSpecimenId={submitterId}&create=true
sample: https://id.example.org/sample/id?submittedProjectId={studyId}&submittedSampleId={submitterId}&create=true
- file: https://id.example.org/object/id?analysisId={analysisId}&fileName={fileName}
validation:
delayMs: 30
diff --git a/song-server/src/main/resources/schemas/analysis/analysisPayload.json b/song-server/src/main/resources/schemas/analysis/analysisPayload.json
index 2cc4a1fe9..436c49cf3 100644
--- a/song-server/src/main/resources/schemas/analysis/analysisPayload.json
+++ b/song-server/src/main/resources/schemas/analysis/analysisPayload.json
@@ -181,6 +181,9 @@
},
"required": [ "study", "analysisType", "sample","file"],
"properties": {
+ "analysisId" :{
+ "not" : {}
+ },
"study" : {
"type": "string",
"minLength": 1
diff --git a/song-server/src/main/resources/schemas/analysis/analysisType.metaschema.json b/song-server/src/main/resources/schemas/analysis/analysisType.metaschema.json
index c456f6529..7fdb465b1 100644
--- a/song-server/src/main/resources/schemas/analysis/analysisType.metaschema.json
+++ b/song-server/src/main/resources/schemas/analysis/analysisType.metaschema.json
@@ -20,6 +20,9 @@
"study" : {
"not" : {}
},
+ "analysisState" : {
+ "not" : {}
+ },
"analysisType" : {
"not" : {}
},
diff --git a/song-server/src/test/java/bio/overture/song/server/controller/AnalysisTypeControllerTest.java b/song-server/src/test/java/bio/overture/song/server/controller/AnalysisTypeControllerTest.java
index 805ed7e64..5c35730c3 100644
--- a/song-server/src/test/java/bio/overture/song/server/controller/AnalysisTypeControllerTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/controller/AnalysisTypeControllerTest.java
@@ -62,6 +62,7 @@
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Supplier;
+import java.util.stream.Stream;
import javax.transaction.Transactional;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@@ -86,6 +87,7 @@
@AutoConfigureMockMvc(secure = false)
@ActiveProfiles({"test"})
public class AnalysisTypeControllerTest {
+ private static final boolean ENABLE_HTTP_LOGGING = false;
// This was done because the autowired mockMvc wasn't working properly, it was getting http 403
// errors
@@ -104,7 +106,7 @@ public class AnalysisTypeControllerTest {
@Before
public void beforeTest() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
- this.endpointTester = createEndpointTester(mockMvc, true);
+ this.endpointTester = createEndpointTester(mockMvc, ENABLE_HTTP_LOGGING);
this.randomGenerator = createRandomGenerator(getClass().getCanonicalName());
}
@@ -570,17 +572,20 @@ public void listAnalysisTypes_filterByMultipleNames_success() {
private void runInvalidRegisterTest(
String filename, String expectedMessage, ServerError expectedServerError) {
- val nonExistingName = generateUniqueName();
val inputInvalidSchema =
FETCHER.readJsonNode(Paths.get("schema-fixtures/invalid").resolve(filename).toString());
+ runInvalidRegisterTest(inputInvalidSchema, expectedMessage, expectedServerError);
+ }
+
+ private void runInvalidRegisterTest(
+ JsonNode invalidSchema, String expectedMessage, ServerError expectedServerError) {
+ val nonExistingName = generateUniqueName();
val registerRequest =
- RegisterAnalysisTypeRequest.builder()
- .name(nonExistingName)
- .schema(inputInvalidSchema)
- .build();
+ RegisterAnalysisTypeRequest.builder().name(nonExistingName).schema(invalidSchema).build();
val songErrorResponse =
endpointTester
.registerAnalysisTypePostRequestAnd(registerRequest)
+ .assertIsError()
.assertServerError(expectedServerError)
.getResponse();
val songError = parseErrorResponse(songErrorResponse);
@@ -647,6 +652,37 @@ public void register_emptySchema_schemaViolation() {
endpointTester.registerAnalysisTypePostRequestAnd(r).assertServerError(SCHEMA_VIOLATION);
}
+ @Test
+ public void register_illegalFields_schemaViolation() {
+ Stream.of(
+ "analysisId",
+ "analysisState",
+ "study",
+ "analysisType",
+ "analysisTypeId",
+ "sample",
+ "file")
+ .forEach(
+ f -> {
+ // Create an invalid schema using one of the invalid fields
+ val inputInvalidSchema =
+ FETCHER.readJsonNode(Paths.get("schema-fixtures/valid.json").toString());
+ val properties = (ObjectNode) inputInvalidSchema.path("properties");
+ val field = properties.putObject(f);
+ field.put("type", "string");
+
+ log.info("Testing illegal field: " + f);
+
+ // Test
+ runInvalidRegisterTest(
+ inputInvalidSchema,
+ "[AnalysisTypeService::schema.violation] - #/properties/"
+ + f
+ + ": subject must not be valid against schema {},#: expected type: Boolean, found: JSONObject",
+ SCHEMA_VIOLATION);
+ });
+ }
+
/** Happy Path: test filtering the listing endpoint by multiple versions only */
@Test
@Transactional
diff --git a/song-server/src/test/java/bio/overture/song/server/controller/EnforcedUploadControllerTest.java b/song-server/src/test/java/bio/overture/song/server/controller/EnforcedUploadControllerTest.java
index 2cd8df7ec..77b7bd18d 100644
--- a/song-server/src/test/java/bio/overture/song/server/controller/EnforcedUploadControllerTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/controller/EnforcedUploadControllerTest.java
@@ -17,15 +17,13 @@
package bio.overture.song.server.controller;
-import static bio.overture.song.core.exceptions.ServerErrors.ANALYSIS_TYPE_INCORRECT_VERSION;
-import static bio.overture.song.core.utils.JsonUtils.objectToTree;
-import static junit.framework.TestCase.assertTrue;
-import static org.junit.Assert.assertEquals;
-
import bio.overture.song.core.model.AnalysisTypeId;
+import bio.overture.song.core.utils.ResourceFetcher;
import bio.overture.song.server.model.dto.UpdateAnalysisRequest;
import bio.overture.song.server.service.AnalysisService;
import bio.overture.song.server.service.StudyService;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.nio.file.Paths;
import lombok.SneakyThrows;
import lombok.val;
import org.junit.Test;
@@ -38,6 +36,16 @@
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.context.WebApplicationContext;
+import java.nio.file.Paths;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static bio.overture.song.core.exceptions.ServerErrors.ANALYSIS_TYPE_INCORRECT_VERSION;
+import static bio.overture.song.core.exceptions.ServerErrors.MALFORMED_PARAMETER;
+import static bio.overture.song.core.exceptions.ServerErrors.SCHEMA_VIOLATION;
+import static bio.overture.song.core.utils.JsonUtils.objectToTree;
+import static bio.overture.song.core.utils.ResourceFetcher.ResourceType.TEST;
+
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc(secure = false)
@ActiveProfiles({"test"})
@@ -49,6 +57,8 @@ public class EnforcedUploadControllerTest extends AbstractEnforcedTester {
@Autowired private StudyService studyService;
@Autowired private AnalysisService analysisService;
+ private static final ResourceFetcher DOCUMENTS_FETCHER =
+ ResourceFetcher.builder().resourceType(TEST).dataDir(Paths.get("documents/")).build();
/** Implementations */
@Override
@@ -73,6 +83,82 @@ public void enforceLatestSubmit_NonLatest_AnalysisTypeIncorrectVersion() {
.assertServerError(ANALYSIS_TYPE_INCORRECT_VERSION);
}
+ @Test
+ public void testInvalidSpecimen() {
+ val j = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s = (ObjectNode) j.get("sample").get(0).get("specimen");
+ s.put("specimenType", "invalid");
+
+ getEndpointTester().submitPostRequestAnd(getStudyId(), j).assertServerError(SCHEMA_VIOLATION);
+
+ val j2 = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s2 = (ObjectNode) j2.get("sample").get(0).get("specimen");
+ s2.put("specimenClass", "invalid");
+ getEndpointTester().submitPostRequestAnd(getStudyId(), j2).assertServerError(SCHEMA_VIOLATION);
+ }
+
+ @Test
+ @SneakyThrows
+ public void testInvalidAnalysisType() {
+
+ // Test invalid analysisType format
+ val j1 = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("validation/variantcall-malformed-analysisType1.json");
+ getEndpointTester()
+ .submitPostRequestAnd(getStudyId(), j1)
+ .assertServerError(MALFORMED_PARAMETER);
+
+ // Test invalid analysisType format
+ val j2 = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("validation/variantcall-malformed-analysisType2.json");
+ getEndpointTester()
+ .submitPostRequestAnd(getStudyId(), j2)
+ .assertServerError(MALFORMED_PARAMETER);
+ }
+
+ @Test
+ @SneakyThrows
+ public void testInvalidSample() {
+ val j = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s = (ObjectNode) j.get("sample").get(0);
+ s.put("sampleType", "invalid");
+
+ getEndpointTester()
+ .submitPostRequestAnd(getStudyId(), j)
+ .assertServerError(SCHEMA_VIOLATION);
+
+ // Test invalid sample format
+ val j2 = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("validation/variantcall-malformed-sample.json");
+ getEndpointTester()
+ .submitPostRequestAnd(getStudyId(), j2)
+ .assertServerError(SCHEMA_VIOLATION);
+ }
+
+ @Test
+ public void testInvalidFile() {
+ val j = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s = (ObjectNode) j.get("file").get(0);
+ s.put("fileType", "invalid");
+ getEndpointTester().submitPostRequestAnd(getStudyId(), j).assertServerError(SCHEMA_VIOLATION);
+
+ val j2 = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s2 = (ObjectNode) j2.get("file").get(0);
+ s2.put("fileAccess", "invalid");
+ getEndpointTester().submitPostRequestAnd(getStudyId(), j2).assertServerError(SCHEMA_VIOLATION);
+
+ val j3 = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s3 = (ObjectNode) j3.get("file").get(0);
+ s3.put("fileMd5sum", "invalid");
+ getEndpointTester().submitPostRequestAnd(getStudyId(), j3).assertServerError(SCHEMA_VIOLATION);
+ }
+
+ @Test
+ public void testInvalidDonor() {
+ val j = (ObjectNode) DOCUMENTS_FETCHER.readJsonNode("variantcall-valid.json");
+ val s = (ObjectNode) j.get("sample").get(0).get("donor");
+ s.put("donorGender", "invalid");
+ getEndpointTester().submitPostRequestAnd(getStudyId(), j).assertServerError(SCHEMA_VIOLATION);
+ // 1) Invalid Gender
+ }
+
@Test
@SneakyThrows
public void enforceLatestPublish_NonLatest_AnalysisTypeIncorrectVersion() {
diff --git a/song-server/src/test/java/bio/overture/song/server/service/FileModificationServiceTest.java b/song-server/src/test/java/bio/overture/song/server/service/FileModificationServiceTest.java
index 5e7d6cfd2..51671a4f8 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/FileModificationServiceTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/FileModificationServiceTest.java
@@ -28,17 +28,13 @@
import static bio.overture.song.core.model.enums.FileUpdateTypes.NO_UPDATE;
import static bio.overture.song.core.model.enums.FileUpdateTypes.resolveFileUpdateType;
import static bio.overture.song.core.utils.RandomGenerator.createRandomGenerator;
-import static bio.overture.song.server.service.FileModificationService.doUnpublish;
import static bio.overture.song.server.utils.TestConstants.DEFAULT_ANALYSIS_ID;
import static bio.overture.song.server.utils.TestConstants.DEFAULT_FILE_ID;
import static bio.overture.song.server.utils.TestConstants.DEFAULT_STUDY_ID;
import static bio.overture.song.server.utils.securestudy.impl.SecureFileTester.createSecureFileTester;
import static com.google.common.collect.Lists.newArrayList;
import static org.icgc.dcc.common.core.json.JsonNodeBuilders.object;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import bio.overture.song.core.model.FileUpdateRequest;
import bio.overture.song.core.model.enums.AccessTypes;
@@ -86,13 +82,6 @@ public void beforeTest() {
this.uniqueMd5 = randomGenerator.generateRandomMD5();
}
- @Test
- public void testDoPublish() {
- assertFalse(doUnpublish(NO_UPDATE));
- assertFalse(doUnpublish(METADATA_UPDATE));
- assertTrue(doUnpublish(CONTENT_UPDATE));
- }
-
@Test
@Transactional
public void testCheckFileUnrelatedToStudy() {
@@ -127,7 +116,7 @@ public void testFileUpdateWithSuppressedAnalysis() {
public void testFileUpdateWithPublishedAnalysis() {
analysisService.securedUpdateState(DEFAULT_STUDY_ID, DEFAULT_ANALYSIS_ID, PUBLISHED);
val originalAnalysis = analysisService.unsecuredDeepRead(DEFAULT_ANALYSIS_ID);
- assertEquals(resolveAnalysisState(originalAnalysis.getAnalysisState()), PUBLISHED);
+ assertEquals(PUBLISHED, resolveAnalysisState(originalAnalysis.getAnalysisState()));
val originalFile =
fileConverter.convertToFileDTO(fileService.securedRead(DEFAULT_STUDY_ID, DEFAULT_FILE_ID));
@@ -137,12 +126,12 @@ public void testFileUpdateWithPublishedAnalysis() {
fileModificationService.securedFileWithAnalysisUpdate(
DEFAULT_STUDY_ID, DEFAULT_FILE_ID, noChangeRequest);
assertFalse(noChangeResponse.isUnpublishedAnalysis());
- assertEquals(noChangeResponse.getFileUpdateType(), NO_UPDATE);
- assertEquals(noChangeResponse.getOriginalAnalysisState(), PUBLISHED);
- assertEquals(noChangeResponse.getOriginalFile(), originalFile);
+ assertEquals(NO_UPDATE, noChangeResponse.getFileUpdateType());
+ assertEquals(PUBLISHED, noChangeResponse.getOriginalAnalysisState());
+ assertEquals(originalFile, noChangeResponse.getOriginalFile());
assertEquals(
- noChangeResponse.getMessage(),
- "Original analysisState 'PUBLISHED' was not changed since the fileUpdateType was 'NO_UPDATE'");
+ "No update for file with objectId 'FI1' and analysisId 'AN1'",
+ noChangeResponse.getMessage());
// Metadata Update
val metadataUpdateRequest =
@@ -160,35 +149,28 @@ public void testFileUpdateWithPublishedAnalysis() {
fileModificationService.securedFileWithAnalysisUpdate(
DEFAULT_STUDY_ID, DEFAULT_FILE_ID, metadataUpdateRequest);
assertFalse(metadataUpdateResponse.isUnpublishedAnalysis());
- assertEquals(metadataUpdateResponse.getFileUpdateType(), METADATA_UPDATE);
- assertEquals(metadataUpdateResponse.getOriginalAnalysisState(), PUBLISHED);
- assertEquals(metadataUpdateResponse.getOriginalFile(), originalFile2);
+ assertEquals(METADATA_UPDATE, metadataUpdateResponse.getFileUpdateType());
+ assertEquals(PUBLISHED, metadataUpdateResponse.getOriginalAnalysisState());
+ assertEquals(originalFile2, metadataUpdateResponse.getOriginalFile());
assertEquals(
- metadataUpdateResponse.getMessage(),
- "Original analysisState 'PUBLISHED' was not changed since the fileUpdateType was 'METADATA_UPDATE'");
+ "Updated file with objectId 'FI1' and analysisId 'AN1'",
+ metadataUpdateResponse.getMessage());
// Content Update
val contentUpdateRequest =
FileUpdateRequest.builder().fileSize(originalFile2.getFileSize() + 77771L).build();
- val originalFile3 =
- fileConverter.convertToFileDTO(fileService.securedRead(DEFAULT_STUDY_ID, DEFAULT_FILE_ID));
- val contentUpdateResponse =
- fileModificationService.securedFileWithAnalysisUpdate(
- DEFAULT_STUDY_ID, DEFAULT_FILE_ID, contentUpdateRequest);
- assertTrue(contentUpdateResponse.isUnpublishedAnalysis());
- assertEquals(contentUpdateResponse.getFileUpdateType(), CONTENT_UPDATE);
- assertEquals(contentUpdateResponse.getOriginalAnalysisState(), PUBLISHED);
- assertEquals(contentUpdateResponse.getOriginalFile(), originalFile3);
- assertEquals(
- contentUpdateResponse.getMessage(),
- "[WARNING]: Changed analysis from 'PUBLISHED' to 'UNPUBLISHED'");
+ SongErrorAssertions.assertSongError(
+ () ->
+ fileModificationService.securedFileWithAnalysisUpdate(
+ DEFAULT_STUDY_ID, DEFAULT_FILE_ID, contentUpdateRequest),
+ ILLEGAL_FILE_UPDATE_REQUEST);
}
@Test
@Transactional
public void testFileUpdateWithUnpublishedAnalysis() {
val originalAnalysis = analysisService.unsecuredDeepRead(DEFAULT_ANALYSIS_ID);
- assertEquals(resolveAnalysisState(originalAnalysis.getAnalysisState()), UNPUBLISHED);
+ assertEquals(UNPUBLISHED, resolveAnalysisState(originalAnalysis.getAnalysisState()));
val originalFile =
fileConverter.convertToFileDTO(fileService.securedRead(DEFAULT_STUDY_ID, DEFAULT_FILE_ID));
@@ -198,10 +180,12 @@ public void testFileUpdateWithUnpublishedAnalysis() {
fileModificationService.securedFileWithAnalysisUpdate(
DEFAULT_STUDY_ID, DEFAULT_FILE_ID, noChangeRequest);
assertFalse(noChangeResponse.isUnpublishedAnalysis());
- assertEquals(noChangeResponse.getFileUpdateType(), NO_UPDATE);
- assertEquals(noChangeResponse.getOriginalAnalysisState(), UNPUBLISHED);
- assertEquals(noChangeResponse.getOriginalFile(), originalFile);
- assertTrue(noChangeResponse.getMessage().contains("Did not change analysisState since it is"));
+ assertEquals(NO_UPDATE, noChangeResponse.getFileUpdateType());
+ assertEquals(UNPUBLISHED, noChangeResponse.getOriginalAnalysisState());
+ assertEquals(originalFile, noChangeResponse.getOriginalFile());
+ assertEquals(
+ "No update for file with objectId 'FI1' and analysisId 'AN1'",
+ noChangeResponse.getMessage());
// Metadata Update
val metadataUpdateRequest =
@@ -219,11 +203,12 @@ public void testFileUpdateWithUnpublishedAnalysis() {
fileModificationService.securedFileWithAnalysisUpdate(
DEFAULT_STUDY_ID, DEFAULT_FILE_ID, metadataUpdateRequest);
assertFalse(metadataUpdateResponse.isUnpublishedAnalysis());
- assertEquals(metadataUpdateResponse.getFileUpdateType(), METADATA_UPDATE);
- assertEquals(metadataUpdateResponse.getOriginalAnalysisState(), UNPUBLISHED);
- assertEquals(metadataUpdateResponse.getOriginalFile(), originalFile2);
- assertTrue(
- metadataUpdateResponse.getMessage().contains("Did not change analysisState since it is"));
+ assertEquals(METADATA_UPDATE, metadataUpdateResponse.getFileUpdateType());
+ assertEquals(UNPUBLISHED, metadataUpdateResponse.getOriginalAnalysisState());
+ assertEquals(originalFile2, metadataUpdateResponse.getOriginalFile());
+ assertEquals(
+ "Updated file with objectId 'FI1' and analysisId 'AN1'",
+ metadataUpdateResponse.getMessage());
// Content Update
val contentUpdateRequest =
@@ -234,11 +219,12 @@ public void testFileUpdateWithUnpublishedAnalysis() {
fileModificationService.securedFileWithAnalysisUpdate(
DEFAULT_STUDY_ID, DEFAULT_FILE_ID, contentUpdateRequest);
assertFalse(contentUpdateResponse.isUnpublishedAnalysis());
- assertEquals(contentUpdateResponse.getFileUpdateType(), CONTENT_UPDATE);
- assertEquals(contentUpdateResponse.getOriginalAnalysisState(), UNPUBLISHED);
- assertEquals(contentUpdateResponse.getOriginalFile(), originalFile3);
- assertTrue(
- contentUpdateResponse.getMessage().contains("Did not change analysisState since it is"));
+ assertEquals(CONTENT_UPDATE, contentUpdateResponse.getFileUpdateType());
+ assertEquals(UNPUBLISHED, contentUpdateResponse.getOriginalAnalysisState());
+ assertEquals(originalFile3, contentUpdateResponse.getOriginalFile());
+ assertEquals(
+ "Updated file with objectId 'FI1' and analysisId 'AN1'",
+ contentUpdateResponse.getMessage());
}
@Test
@@ -314,9 +300,9 @@ public void testUpdateWithRequests() {
val goldenFile = converter.copyFile(referenceFile);
val u1 = FileUpdateRequest.builder().fileAccess("controlled").build();
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), METADATA_UPDATE);
+ assertEquals(METADATA_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setInfo(
object()
@@ -324,63 +310,63 @@ public void testUpdateWithRequests() {
randomGenerator.generateRandomUUIDAsString(),
randomGenerator.generateRandomUUIDAsString())
.end());
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), METADATA_UPDATE);
+ assertEquals(METADATA_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileAccess("open");
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), METADATA_UPDATE);
+ assertEquals(METADATA_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileAccess(null);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), METADATA_UPDATE);
+ assertEquals(METADATA_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileSize(19191L);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileMd5sum(randomGenerator.generateRandomMD5());
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setInfo(null);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileAccess(null);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileMd5sum(uniqueMd5);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileMd5sum(null);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileSize(referenceFile.getFileSize());
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), NO_UPDATE);
+ assertEquals(NO_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
u1.setFileSize(null);
- assertEquals(fileModificationService.updateWithRequest(referenceFile, u1), NO_UPDATE);
+ assertEquals(NO_UPDATE, fileModificationService.updateWithRequest(referenceFile, u1));
assertNull(u1.getFileAccess());
assertNull(u1.getFileSize());
assertNull(u1.getFileMd5sum());
assertNull(u1.getInfo());
assertFalse(referenceFile == goldenFile);
- assertEquals(referenceFile, goldenFile);
+ assertEquals(goldenFile, referenceFile);
}
@Test
@@ -391,38 +377,38 @@ public void testFileUpdateTypeResolution() {
// update access field
val u1 = FileUpdateRequest.builder().fileAccess("controlled").build();
- assertEquals(resolveFileUpdateType(f1, u1), METADATA_UPDATE);
+ assertEquals(METADATA_UPDATE, resolveFileUpdateType(f1, u1));
// update info field
u1.setInfo(object().with("myInfoKey2", "myInfoValue2").end());
- assertEquals(resolveFileUpdateType(f1, u1), METADATA_UPDATE);
+ assertEquals(METADATA_UPDATE, resolveFileUpdateType(f1, u1));
// update file size
val u2 = FileUpdateRequest.builder().fileSize(123123L).build();
u1.setFileSize(123456L);
// test request u1 with metadata updates
- assertEquals(resolveFileUpdateType(f1, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, resolveFileUpdateType(f1, u1));
// test request u2 without any metadata updates
- assertEquals(resolveFileUpdateType(f1, u2), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, resolveFileUpdateType(f1, u2));
// update file md5
u2.setFileMd5sum(randomGenerator.generateRandomMD5());
u1.setFileMd5sum(randomGenerator.generateRandomMD5());
// test request u1 with metadata updates
- assertEquals(resolveFileUpdateType(f1, u1), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, resolveFileUpdateType(f1, u1));
// test request u2 without any metadata updates
- assertEquals(resolveFileUpdateType(f1, u2), CONTENT_UPDATE);
+ assertEquals(CONTENT_UPDATE, resolveFileUpdateType(f1, u2));
// test nulls
val u3 = FileUpdateRequest.builder().build();
- assertEquals(resolveFileUpdateType(f1, u3), NO_UPDATE);
+ assertEquals(NO_UPDATE, resolveFileUpdateType(f1, u3));
u3.setFileMd5sum(f1.getFileMd5sum());
u3.setFileSize(f1.getFileSize());
u3.setFileAccess(f1.getFileAccess());
u3.setInfo(f1.getInfo());
- assertEquals(resolveFileUpdateType(f1, u3), NO_UPDATE);
+ assertEquals(NO_UPDATE, resolveFileUpdateType(f1, u3));
- assertEquals(f1, golden);
+ assertEquals(golden, f1);
}
private FileEntity buildReferenceFile() {
diff --git a/song-server/src/test/java/bio/overture/song/server/service/FileServiceTest.java b/song-server/src/test/java/bio/overture/song/server/service/FileServiceTest.java
index 928d14d12..3fceb3348 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/FileServiceTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/FileServiceTest.java
@@ -20,7 +20,7 @@
import static bio.overture.song.core.exceptions.ServerErrors.STUDY_ID_DOES_NOT_EXIST;
import static bio.overture.song.core.model.enums.AccessTypes.CONTROLLED;
import static bio.overture.song.core.model.enums.AccessTypes.OPEN;
-import static bio.overture.song.core.testing.SongErrorAssertions.assertExceptionThrownBy;
+import static bio.overture.song.core.model.enums.FileTypes.FAI;
import static bio.overture.song.core.testing.SongErrorAssertions.assertSongError;
import static bio.overture.song.core.utils.RandomGenerator.createRandomGenerator;
import static bio.overture.song.server.utils.TestConstants.DEFAULT_ANALYSIS_ID;
@@ -105,7 +105,7 @@ public void testCreateAndDeleteFile() {
f.setStudyId(studyId);
f.setFileSize(0L);
- f.setFileType("FAI");
+ f.setFileType(FAI);
f.setFileMd5sum("6bb8ee7218e96a59e0ad898b4f5360f1");
f.setInfo(metadata);
f.setFileAccess(OPEN);
@@ -160,23 +160,6 @@ public void testSaveFileAsTgz() {
assertEquals(updatedFile, actualFile);
}
- @Test
- public void testCreateFileUnknownType() {
- assertExceptionThrownBy(
- IllegalStateException.class,
- () ->
- FileEntity.builder()
- .fileAccess("controlled")
- .fileMd5sum(randomGenerator.generateRandomMD5())
- .fileName(randomGenerator.generateRandomAsciiString(10))
- .fileSize((long) randomGenerator.generateRandomInt(100, 100000))
- .analysisId(randomGenerator.generateRandomUUIDAsString())
- .objectId(randomGenerator.generateRandomUUIDAsString())
- .studyId(randomGenerator.generateRandomAsciiString(7))
- .fileType("TGZZZZZ")
- .build());
- }
-
@Test
public void testUpdateFile() {
diff --git a/song-server/src/test/java/bio/overture/song/server/service/SerializationTest.java b/song-server/src/test/java/bio/overture/song/server/service/SerializationTest.java
index 5fb417b73..c27597f23 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/SerializationTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/SerializationTest.java
@@ -248,29 +248,6 @@ public void testDonorValues() {
assertEquals(json, expectedJson);
}
- @Test
- public void testInvalidValues() {
- val id = "DO000123";
- val submitterId = "123";
- val studyId = "X23-CA";
- val gender = "potatoes";
-
- boolean failed = false;
- try {
- val donor =
- Donor.builder()
- .donorId(id)
- .donorSubmitterId(submitterId)
- .studyId(studyId)
- .donorGender(gender)
- .build();
- } catch (IllegalArgumentException e) {
- failed = true;
- }
-
- assertTrue(failed);
- }
-
@Test
public void testListFile() throws IOException {
val singleQuotedJson =
diff --git a/song-server/src/test/java/bio/overture/song/server/service/UploadServiceTest.java b/song-server/src/test/java/bio/overture/song/server/service/UploadServiceTest.java
index 6787925ff..fd2836f76 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/UploadServiceTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/UploadServiceTest.java
@@ -17,10 +17,12 @@
package bio.overture.song.server.service;
import static bio.overture.song.core.exceptions.ServerErrors.PAYLOAD_PARSING;
+import static bio.overture.song.core.exceptions.ServerErrors.SCHEMA_VIOLATION;
import static bio.overture.song.core.testing.SongErrorAssertions.assertSongError;
import static bio.overture.song.core.utils.JsonUtils.fromJson;
import static bio.overture.song.core.utils.JsonUtils.toJson;
import static bio.overture.song.core.utils.RandomGenerator.createRandomGenerator;
+import static bio.overture.song.server.model.enums.ModelAttributeNames.ANALYSIS_ID;
import static bio.overture.song.server.utils.TestAnalysis.extractBoolean;
import static bio.overture.song.server.utils.TestAnalysis.extractNode;
import static bio.overture.song.server.utils.TestAnalysis.extractString;
@@ -45,6 +47,7 @@
import bio.overture.song.server.repository.UploadRepository;
import bio.overture.song.server.service.id.IdService;
import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Map;
import javax.transaction.Transactional;
@@ -139,6 +142,16 @@ public void submit_CorruptedPayload_PayloadParsingError() {
assertSongError(() -> uploadService.submit(DEFAULT_STUDY, corruptedPayload), PAYLOAD_PARSING);
}
+ @Test
+ @SneakyThrows
+ public void submit_AnalysisIdInPayload_SchemaValidationError() {
+ val p = createPayloadWithDifferentAnalysisId();
+ val invalidPayload = (ObjectNode) new ObjectMapper().readTree(p.getJsonPayload());
+ invalidPayload.put(ANALYSIS_ID, p.getAnalysisId());
+ assertSongError(
+ () -> uploadService.submit(DEFAULT_STUDY, invalidPayload.toString()), SCHEMA_VIOLATION);
+ }
+
@Test
@Transactional
public void testSave2PayloadsWithSameSpecimen() {
@@ -219,13 +232,6 @@ private InternalPayload createPayloadWithDifferentAnalysisId() {
return InternalPayload.builder().analysisId(analysisId).jsonPayload(jsonPayload).build();
}
- @SneakyThrows
- private void test(String fileName) {
- val jsonPayload = getJsonStringFromClasspath(fileName);
- val response = uploadService.submit(DEFAULT_STUDY, jsonPayload);
- assertEquals(Responses.OK, response.getStatus());
- }
-
@Value
@Builder
private static class InternalPayload {
diff --git a/song-server/src/test/java/bio/overture/song/server/service/id/FederatedIdServiceTest.java b/song-server/src/test/java/bio/overture/song/server/service/id/FederatedIdServiceTest.java
index 8e6048ae5..dcb10d501 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/id/FederatedIdServiceTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/id/FederatedIdServiceTest.java
@@ -12,10 +12,14 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import bio.overture.song.core.utils.RandomGenerator;
import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
import lombok.val;
import org.apache.commons.lang.NotImplementedException;
import org.junit.Before;
@@ -47,7 +51,6 @@ enum MODE {
private static final String DONOR_URL = "https://example.org/donor/id";
private static final String SPECIMEN_URL = "https://example.org/specimen/id";
private static final String SAMPLE_URL = "https://example.org/sample/id";
- private static final String FILE_URL = "https://example.org/file/id";
/** Mocks */
@Mock private RestClient restClient;
@@ -132,25 +135,15 @@ public void getSample_otherError_IdServiceError() {
}
@Test
- public void getFile_existing_id() {
- setupFile(GOOD);
- val fileResult = idService.getFileId(DEFAULT_ANALYSIS_ID, DEFAULT_FILE_NAME);
- assertTrue(fileResult.isPresent());
- assertEquals(fileResult.get(), DEFAULT_ID);
- }
-
- @Test
- public void getFile_nonExisting_emptyResult() {
- setupFile(NOT_FOUND);
- val fileResult = idService.getFileId(DEFAULT_ANALYSIS_ID, DEFAULT_FILE_NAME);
- assertFalse(fileResult.isPresent());
- }
-
- @Test
- public void getFile_otherError_IdServiceError() {
- setupFile(ERROR);
- assertSongError(
- () -> idService.getFileId(DEFAULT_ANALYSIS_ID, DEFAULT_FILE_NAME), ID_SERVICE_ERROR);
+ public void testFileId() {
+ val expectedObjectId = UUID.randomUUID().toString();
+ when(localIdService.getFileId(DEFAULT_ANALYSIS_ID, DEFAULT_FILE_NAME))
+ .thenReturn(Optional.of(expectedObjectId));
+ val result = idService.getFileId(DEFAULT_ANALYSIS_ID, DEFAULT_FILE_NAME);
+ assertTrue(result.isPresent());
+ val actualObjectId = result.get();
+ assertEquals(actualObjectId, expectedObjectId);
+ verify(localIdService, times(1)).getFileId(DEFAULT_ANALYSIS_ID, DEFAULT_FILE_NAME);
}
@Test
@@ -176,11 +169,6 @@ private void setupSample(MODE mode) {
when(uriResolver.expandSampleUri(anyString(), anyString())).thenReturn(SAMPLE_URL);
}
- private void setupFile(MODE mode) {
- baseSetup(mode, FILE_URL);
- when(uriResolver.expandFileUri(anyString(), anyString())).thenReturn(FILE_URL);
- }
-
private HttpStatusCodeException generateNonNotFoundStatusCodeException() {
val nonNotFoundError =
randomGenerator.shuffleList(List.of(HttpStatus.values())).stream()
diff --git a/song-server/src/test/java/bio/overture/song/server/service/id/LocalIdServiceTest.java b/song-server/src/test/java/bio/overture/song/server/service/id/LocalIdServiceTest.java
index 0d44a8a4c..0310599be 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/id/LocalIdServiceTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/id/LocalIdServiceTest.java
@@ -35,7 +35,6 @@ public class LocalIdServiceTest {
private static final Optional ID_A = Optional.of("8540ebac-66f2-553a-b865-0d3006edd892");
private static final Optional ID_B = Optional.of("57f844eb-4ab4-5d3d-8dc1-8b7a463e20c1");
private static final Optional ID_C = Optional.of("b4f5aea1-1f4c-5e12-8557-76dbadb26239");
- private static final String UUID1 = "b7f5aea7-1f4c-5e12-8557-76dbadb26333";
private LocalIdService localIdService;
diff --git a/song-server/src/test/java/bio/overture/song/server/service/id/UriResolverTest.java b/song-server/src/test/java/bio/overture/song/server/service/id/UriResolverTest.java
index 4fc97fcc6..cccb49879 100644
--- a/song-server/src/test/java/bio/overture/song/server/service/id/UriResolverTest.java
+++ b/song-server/src/test/java/bio/overture/song/server/service/id/UriResolverTest.java
@@ -56,11 +56,6 @@ public void testUnknownTemplateVariable() {
bad.setSample(good.getSample() + "&something={someVar}");
assertOnlyUnknownVariables(bad, "someVar");
bad.setSample(good.getSample());
-
- // Test file
- bad.setFile(good.getFile() + "&something={someVar}");
- assertOnlyUnknownVariables(bad, "someVar");
- bad.setFile(good.getFile());
}
@Test
@@ -82,11 +77,6 @@ public void testMissingTemplateVariable() {
bad.setSample("https://example.org/proj={studyId}");
assertOnlyMissingVariables(bad, "submitterId");
bad.setSample(good.getSample());
-
- // Test file
- bad.setFile("https://example.org/an={analysisId}");
- assertOnlyMissingVariables(bad, "fileName");
- bad.setFile(good.getFile());
}
private static void assertOnlyMissingVariables(UriTemplateProperties p, String... variables) {
@@ -122,10 +112,6 @@ private static void assertGood(UriResolver ur) {
assertEquals(
"https://example.org?sid=subSample123&proj=ABC123-CA",
ur.expandSampleUri("ABC123-CA", "subSample123"));
-
- assertEquals(
- "https://example.org?anid=AN01&fname=my-file.vcf.gz",
- ur.expandFileUri("AN01", "my-file.vcf.gz"));
}
private static void assertExceptionThrown(
diff --git a/song-server/src/test/java/bio/overture/song/server/utils/web/ResponseOption.java b/song-server/src/test/java/bio/overture/song/server/utils/web/ResponseOption.java
index 6f52a5db0..f81615350 100644
--- a/song-server/src/test/java/bio/overture/song/server/utils/web/ResponseOption.java
+++ b/song-server/src/test/java/bio/overture/song/server/utils/web/ResponseOption.java
@@ -20,6 +20,7 @@
import static bio.overture.song.core.exceptions.SongError.parseErrorResponse;
import static bio.overture.song.core.utils.Deserialization.deserializeList;
import static bio.overture.song.core.utils.Deserialization.deserializePage;
+import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -70,6 +71,15 @@ public Set extractManyEntities(@NonNull Class entityClass) {
.map(x -> internalExtractManyEntitiesFromResponse(x, entityClass));
}
+ public ResponseOption assertIsError() {
+ assertTrue(
+ format(
+ "Was expecting an error (4xx or 5xx status code), " + "however status code was [%s]",
+ response.getStatusCode()),
+ response.getStatusCode().isError());
+ return this;
+ }
+
public ResponseOption assertServerError(ServerError serverError) {
val songError = parseErrorResponse(response);
assertEquals(serverError.getErrorId(), songError.getErrorId());
diff --git a/song-server/src/test/resources/documents/uriResolver/good.json b/song-server/src/test/resources/documents/uriResolver/good.json
index c844821ff..e5f0a7cf7 100644
--- a/song-server/src/test/resources/documents/uriResolver/good.json
+++ b/song-server/src/test/resources/documents/uriResolver/good.json
@@ -1,7 +1,6 @@
{
"donor" : "https://example.org?sid={submitterId}&proj={studyId}",
"specimen" : "https://example.org?sid={submitterId}&proj={studyId}",
- "sample" : "https://example.org?sid={submitterId}&proj={studyId}",
- "file" : "https://example.org?anid={analysisId}&fname={fileName}"
+ "sample" : "https://example.org?sid={submitterId}&proj={studyId}"
}
diff --git a/song-server/src/test/resources/documents/validation/dynamic-analysis-type/rendered-schema.json b/song-server/src/test/resources/documents/validation/dynamic-analysis-type/rendered-schema.json
index 7c74a157a..f5c7d6298 100644
--- a/song-server/src/test/resources/documents/validation/dynamic-analysis-type/rendered-schema.json
+++ b/song-server/src/test/resources/documents/validation/dynamic-analysis-type/rendered-schema.json
@@ -181,6 +181,9 @@
},
"required": [ "study", "analysisType","experiment","sample","file", "firstName"],
"properties": {
+ "analysisId" : {
+ "not" : {}
+ },
"study" : {
"type": "string",
"minLength": 1
diff --git a/song-server/src/test/resources/documents/validation/variantcall-malformed-analysisType1.json b/song-server/src/test/resources/documents/validation/variantcall-malformed-analysisType1.json
new file mode 100644
index 000000000..8d714b52f
--- /dev/null
+++ b/song-server/src/test/resources/documents/validation/variantcall-malformed-analysisType1.json
@@ -0,0 +1,42 @@
+{
+ "study": "ABC123",
+ "analysisType" : "variantCall",
+ "experiment": {
+ "variantCallingTool": "silver bullet",
+ "matchedNormalSampleSubmitterId": "sample x24-11a"
+ },
+ "sample": [
+ {
+ "sampleSubmitterId": "internal_sample_98024759826836",
+ "sampleType": "Total RNA",
+ "specimen": {
+ "specimenSubmitterId": "internal_specimen_9b73gk8s02dk",
+ "specimenClass": "Tumour",
+ "specimenType": "Primary tumour - other"
+ },
+ "donor": {
+ "donorSubmitterId": "internal_donor_123456789-00",
+ "donorGender": "female"
+ }
+ }
+ ],
+ "file": [
+ {
+ "fileName": "a3bc0998a-3521-43fd-fa10-a834f3874e46.MUSE_1-0rc-vcf.20170711.somatic.snv_mnv.vcf.gz",
+ "fileSize": 376953,
+ "fileMd5sum": "61a91c4bf04ac2bd3795254104f75ad3",
+ "fileAccess" : "open",
+ "fileType": "VCF"
+ },
+ {
+ "fileName": "a3bc0998a-3521-43fd-fa10-a834f3874e46.MUSE_1-0rc-vcf.20170711.somatic.snv_mnv.vcf.gz.idx",
+ "fileSize": 4840,
+ "fileMd5sum": "61a91c4bf04bb54d3795254104f75ad3",
+ "fileAccess" : "open",
+ "fileType": "IDX"
+ }
+ ],
+ "info": {
+ "description": "This is extra info in a JSON format"
+ }
+}
\ No newline at end of file
diff --git a/song-server/src/test/resources/documents/validation/variantcall-malformed-analysisType2.json b/song-server/src/test/resources/documents/validation/variantcall-malformed-analysisType2.json
new file mode 100644
index 000000000..b48271b3f
--- /dev/null
+++ b/song-server/src/test/resources/documents/validation/variantcall-malformed-analysisType2.json
@@ -0,0 +1,41 @@
+{
+ "study": "ABC123",
+ "experiment": {
+ "variantCallingTool": "silver bullet",
+ "matchedNormalSampleSubmitterId": "sample x24-11a"
+ },
+ "sample": [
+ {
+ "sampleSubmitterId": "internal_sample_98024759826836",
+ "sampleType": "Total RNA",
+ "specimen": {
+ "specimenSubmitterId": "internal_specimen_9b73gk8s02dk",
+ "specimenClass": "Tumour",
+ "specimenType": "Primary tumour - other"
+ },
+ "donor": {
+ "donorSubmitterId": "internal_donor_123456789-00",
+ "donorGender": "female"
+ }
+ }
+ ],
+ "file": [
+ {
+ "fileName": "a3bc0998a-3521-43fd-fa10-a834f3874e46.MUSE_1-0rc-vcf.20170711.somatic.snv_mnv.vcf.gz",
+ "fileSize": 376953,
+ "fileMd5sum": "61a91c4bf04ac2bd3795254104f75ad3",
+ "fileAccess" : "open",
+ "fileType": "VCF"
+ },
+ {
+ "fileName": "a3bc0998a-3521-43fd-fa10-a834f3874e46.MUSE_1-0rc-vcf.20170711.somatic.snv_mnv.vcf.gz.idx",
+ "fileSize": 4840,
+ "fileMd5sum": "61a91c4bf04bb54d3795254104f75ad3",
+ "fileAccess" : "open",
+ "fileType": "IDX"
+ }
+ ],
+ "info": {
+ "description": "This is extra info in a JSON format"
+ }
+}
\ No newline at end of file
diff --git a/song-server/src/test/resources/documents/validation/variantcall-malformed-sample.json b/song-server/src/test/resources/documents/validation/variantcall-malformed-sample.json
new file mode 100644
index 000000000..4b70620f0
--- /dev/null
+++ b/song-server/src/test/resources/documents/validation/variantcall-malformed-sample.json
@@ -0,0 +1,43 @@
+{
+ "study": "ABC123",
+ "analysisType" : {
+ "name" : "variantCall",
+ "version" : 1
+ },
+ "experiment": {
+ "variantCallingTool": "silver bullet",
+ "matchedNormalSampleSubmitterId": "sample x24-11a"
+ },
+ "sample": {
+ "sampleSubmitterId": "internal_sample_98024759826836",
+ "sampleType": "Total RNA",
+ "specimen": {
+ "specimenSubmitterId": "internal_specimen_9b73gk8s02dk",
+ "specimenClass": "Tumour",
+ "specimenType": "Primary tumour - other"
+ },
+ "donor": {
+ "donorSubmitterId": "internal_donor_123456789-00",
+ "donorGender": "female"
+ }
+ } ,
+ "file": [
+ {
+ "fileName": "a3bc0998a-3521-43fd-fa10-a834f3874e46.MUSE_1-0rc-vcf.20170711.somatic.snv_mnv.vcf.gz",
+ "fileSize": 376953,
+ "fileMd5sum": "61a91c4bf04ac2bd3795254104f75ad3",
+ "fileAccess" : "open",
+ "fileType": "VCF"
+ },
+ {
+ "fileName": "a3bc0998a-3521-43fd-fa10-a834f3874e46.MUSE_1-0rc-vcf.20170711.somatic.snv_mnv.vcf.gz.idx",
+ "fileSize": 4840,
+ "fileMd5sum": "61a91c4bf04bb54d3795254104f75ad3",
+ "fileAccess" : "open",
+ "fileType": "IDX"
+ }
+ ],
+ "info": {
+ "description": "This is extra info in a JSON format"
+ }
+}
\ No newline at end of file