use of org.sagebionetworks.bridge.models.upload.UploadFieldDefinition in project BridgeServer2 by Sage-Bionetworks.
the class DynamoAppTest method uploadMetadataFieldDefListIsNeverNull.
@Test
public void uploadMetadataFieldDefListIsNeverNull() {
// make field for test
List<UploadFieldDefinition> fieldDefList = new ArrayList<>();
fieldDefList.add(new UploadFieldDefinition.Builder().withName("test-field").withType(UploadFieldType.ATTACHMENT_V2).build());
// starts as empty
App app = new DynamoApp();
assertTrue(app.getUploadMetadataFieldDefinitions().isEmpty());
// set value works
app.setUploadMetadataFieldDefinitions(fieldDefList);
assertEquals(app.getUploadMetadataFieldDefinitions(), fieldDefList);
// set to null makes it empty again
app.setUploadMetadataFieldDefinitions(null);
assertTrue(app.getUploadMetadataFieldDefinitions().isEmpty());
}
use of org.sagebionetworks.bridge.models.upload.UploadFieldDefinition in project BridgeServer2 by Sage-Bionetworks.
the class HealthDataServiceSubmitHealthDataTest method submitHealthDataBySchema.
@Test
public void submitHealthDataBySchema() throws Exception {
// mock schema service
List<UploadFieldDefinition> fieldDefList = ImmutableList.of(new UploadFieldDefinition.Builder().withName("sanitize____this").withType(UploadFieldType.STRING).build(), new UploadFieldDefinition.Builder().withName("no-value-field").withType(UploadFieldType.STRING).withRequired(false).build(), new UploadFieldDefinition.Builder().withName("null-value-field").withType(UploadFieldType.STRING).withRequired(false).build(), new UploadFieldDefinition.Builder().withName("attachment-field").withType(UploadFieldType.ATTACHMENT_V2).build(), new UploadFieldDefinition.Builder().withName("normal-field").withType(UploadFieldType.STRING).build());
schema.setFieldDefinitions(fieldDefList);
// setup input
ObjectNode inputData = BridgeObjectMapper.get().createObjectNode();
inputData.put("sanitize!@#$this", "sanitize this value");
inputData.putNull("null-value-field");
inputData.put("attachment-field", "attachment field value");
inputData.put("normal-field", "normal field value");
inputData.put("non-schema-field", "this is not in the schema");
ObjectNode inputMetadata = BridgeObjectMapper.get().createObjectNode();
inputMetadata.put("sample-metadata-key", "sample-metadata-value");
HealthDataSubmission submission = makeValidBuilderWithSchema().withData(inputData).withMetadata(inputMetadata).build();
// execute
HealthDataRecord svcOutputRecord = svc.submitHealthData(TEST_APP_ID, PARTICIPANT, submission);
// verify that we return the record returned by the internal getRecordById() call.
assertSame(svcOutputRecord, createdRecord);
// Verify strict validation handler called. While we're at it, verify that we constructed the context and
// record correctly.
ArgumentCaptor<UploadValidationContext> contextCaptor = ArgumentCaptor.forClass(UploadValidationContext.class);
verify(mockStrictValidationHandler).handle(contextCaptor.capture());
UploadValidationContext context = contextCaptor.getValue();
assertEquals(context.getHealthCode(), HEALTH_CODE);
assertEquals(context.getAppId(), TEST_APP_ID);
// We generate an upload ID and use it for the record ID.
String uploadId = context.getUploadId();
assertNotNull(uploadId);
assertEquals(context.getRecordId(), uploadId);
// We have one attachment. This is text because we passed in text. This will normally be arrays or objects.
ArgumentCaptor<JsonNode> attachmentNodeCaptor = ArgumentCaptor.forClass(JsonNode.class);
verify(mockUploadFileHelper).uploadJsonNodeAsAttachment(attachmentNodeCaptor.capture(), eq(uploadId), eq("attachment-field"));
JsonNode attachmentNode = attachmentNodeCaptor.getValue();
assertEquals(attachmentNode.textValue(), "attachment field value");
// validate the created record
HealthDataRecord contextRecord = context.getHealthDataRecord();
assertEquals(contextRecord.getAppVersion(), APP_VERSION);
assertEquals(contextRecord.getPhoneInfo(), PHONE_INFO);
assertEquals(contextRecord.getSchemaId(), SCHEMA_ID);
assertEquals(contextRecord.getSchemaRevision().intValue(), SCHEMA_REV);
assertEquals(contextRecord.getHealthCode(), HEALTH_CODE);
assertEquals(contextRecord.getAppId(), TEST_APP_ID);
assertEquals(contextRecord.getUploadDate(), MOCK_NOW_DATE);
assertEquals(contextRecord.getUploadedOn().longValue(), MOCK_NOW_MILLIS);
assertEquals(contextRecord.getCreatedOn().longValue(), CREATED_ON_MILLIS);
assertEquals(contextRecord.getCreatedOnTimeZone(), CREATED_ON_TIMEZONE);
// validate the sanitized data (includes attachments with attachment ID)
JsonNode sanitizedData = contextRecord.getData();
assertEquals(sanitizedData.size(), 3);
assertEquals(sanitizedData.get("sanitize____this").textValue(), "sanitize this value");
assertEquals(sanitizedData.get("attachment-field"), ATTACHMENT_ID_NODE);
assertEquals(sanitizedData.get("normal-field").textValue(), "normal field value");
// validate app version and phone info in metadata
JsonNode metadata = contextRecord.getMetadata();
assertEquals(metadata.size(), 2);
assertEquals(metadata.get(UploadUtil.FIELD_APP_VERSION).textValue(), APP_VERSION);
assertEquals(metadata.get(UploadUtil.FIELD_PHONE_INFO).textValue(), PHONE_INFO);
// validate client-submitted metadata (userMetadata)
JsonNode userMetadata = contextRecord.getUserMetadata();
assertEquals(userMetadata.size(), 1);
assertEquals(userMetadata.get("sample-metadata-key").textValue(), "sample-metadata-value");
// Validate raw data submitted to S3
String expectedRawDataAttachmentId = uploadId + HealthDataService.RAW_ATTACHMENT_SUFFIX;
ArgumentCaptor<byte[]> rawBytesCaptor = ArgumentCaptor.forClass(byte[].class);
verify(mockUploadFileHelper).uploadBytesAsAttachment(eq(expectedRawDataAttachmentId), rawBytesCaptor.capture());
assertEquals(contextRecord.getRawDataAttachmentId(), expectedRawDataAttachmentId);
byte[] rawBytes = rawBytesCaptor.getValue();
JsonNode rawJsonNode = BridgeObjectMapper.get().readTree(rawBytes);
assertEquals(rawJsonNode, inputData);
// validate the other handlers are called
verify(mockTranscribeConsentHandler).handle(context);
verify(mockUploadArtifactsHandler).handle(context);
// We get the record back using the upload ID.
verify(svc).getRecordById(uploadId);
}
use of org.sagebionetworks.bridge.models.upload.UploadFieldDefinition in project BridgeServer2 by Sage-Bionetworks.
the class HealthDataServiceSubmitHealthDataTest method strictValidationThrows.
@Test(expectedExceptions = BadRequestException.class)
public void strictValidationThrows() throws Exception {
// mock schema service
List<UploadFieldDefinition> fieldDefList = ImmutableList.of(new UploadFieldDefinition.Builder().withName("simple-field").withType(UploadFieldType.INT).build());
schema.setFieldDefinitions(fieldDefList);
// mock handlers - Only StrictValidationHandler will be called. Also, since we're not calling the actual
// StrictValidationHandler, we need to make it throw.
doThrow(UploadValidationException.class).when(mockStrictValidationHandler).handle(any());
// setup input
ObjectNode inputData = BridgeObjectMapper.get().createObjectNode();
inputData.put("simple-field", "not an int");
HealthDataSubmission submission = makeValidBuilderWithSchema().withData(inputData).build();
// execute - This throws.
svc.submitHealthData(TEST_APP_ID, PARTICIPANT, submission);
}
use of org.sagebionetworks.bridge.models.upload.UploadFieldDefinition in project BridgeServer2 by Sage-Bionetworks.
the class UploadSchemaService method createUploadSchemaFromSurvey.
/**
* <p>
* Creates an upload schema from a survey. This is generally called when a survey is published, to
* create the corresponding upload schema, so that health data records can be created from survey responses.
* This method will also persist the schema to the backing store.
* <p>
* If newSchemaRev is true, this method will always create a new schema revision. If false, it will attempt to
* modify the existing schema revision. However, if the schema revisions are not compatible, it will fall back to
* creating a new schema revision.
* </p>
*/
public UploadSchema createUploadSchemaFromSurvey(String appId, Survey survey, boolean newSchemaRev) {
// https://sagebionetworks.jira.com/browse/BRIDGE-1698 - If the existing Schema ID points to a different survey
// or a non-survey, this is an error. Having multiple surveys point to the same schema ID causes really bad
// things to happen, and we need to prevent it.
String schemaId = survey.getIdentifier();
UploadSchema oldSchema = getUploadSchemaNoThrow(appId, schemaId);
if (oldSchema != null) {
if (oldSchema.getSchemaType() != UploadSchemaType.IOS_SURVEY || !Objects.equals(oldSchema.getSurveyGuid(), survey.getGuid())) {
throw new BadRequestException("Survey with identifier " + schemaId + " conflicts with schema with the same ID. Please use a different survey identifier.");
}
}
// the same survey.
if (!newSchemaRev && oldSchema != null) {
// Check that the old schema already has the answers field.
List<UploadFieldDefinition> oldFieldDefList = oldSchema.getFieldDefinitions();
UploadFieldDefinition answersFieldDef = getElement(oldFieldDefList, UploadFieldDefinition::getName, FIELD_ANSWERS).orElse(null);
if (answersFieldDef == null) {
// Old schema doesn't have the
List<UploadFieldDefinition> newFieldDefList = new ArrayList<>(oldFieldDefList);
newFieldDefList.add(UploadUtil.ANSWERS_FIELD_DEF);
addSurveySchemaMetadata(oldSchema, survey);
oldSchema.setFieldDefinitions(newFieldDefList);
return updateSchemaRevisionV4(appId, schemaId, oldSchema.getRevision(), oldSchema);
}
// Answers field needs to be either
// (a) an attachment (Large Text or normal)
// (b) a string with isUnboundedLength=true
UploadFieldType fieldType = answersFieldDef.getType();
if (fieldType == UploadFieldType.LARGE_TEXT_ATTACHMENT || UploadFieldType.ATTACHMENT_TYPE_SET.contains(fieldType) || (UploadFieldType.STRING_TYPE_SET.contains(fieldType) && Boolean.TRUE.equals(answersFieldDef.isUnboundedText()))) {
// The old schema works for the new survey. However, we want to ensure the old schema points to the
// latest version of the survey. Update survey metadata in the schema.
addSurveySchemaMetadata(oldSchema, survey);
return updateSchemaRevisionV4(appId, schemaId, oldSchema.getRevision(), oldSchema);
}
// If execution gets this far, that means we have a schema with an "answers" field that's not compatible.
// At this point, we go into the branch that creates a new schema, below.
}
// We were unable to reconcile this with the existing schema. Create a new schema. (Create API will
// automatically bump the rev number if an old schema revision exists.)
UploadSchema schemaToCreate = UploadSchema.create();
addSurveySchemaMetadata(schemaToCreate, survey);
schemaToCreate.setFieldDefinitions(ImmutableList.of(UploadUtil.ANSWERS_FIELD_DEF));
return createSchemaRevisionV4(appId, schemaToCreate);
}
use of org.sagebionetworks.bridge.models.upload.UploadFieldDefinition in project BridgeServer2 by Sage-Bionetworks.
the class AppServiceTest method updateUploadMetadataCanAddAndReorderFields.
@Test
public void updateUploadMetadataCanAddAndReorderFields() {
// make fields for test
UploadFieldDefinition reorderedField1 = new UploadFieldDefinition.Builder().withName("reoredered-field-1").withType(UploadFieldType.INT).build();
UploadFieldDefinition reorderedField2 = new UploadFieldDefinition.Builder().withName("reoredered-field-2").withType(UploadFieldType.BOOLEAN).build();
UploadFieldDefinition addedField = new UploadFieldDefinition.Builder().withName("added-field").withType(UploadFieldType.TIMESTAMP).build();
// old app
App oldApp = getTestApp();
oldApp.setUploadMetadataFieldDefinitions(ImmutableList.of(reorderedField1, reorderedField2));
when(mockAppDao.getApp(TEST_APP_ID)).thenReturn(oldApp);
// new app
App newApp = getTestApp();
newApp.setUploadMetadataFieldDefinitions(ImmutableList.of(reorderedField2, reorderedField1, addedField));
// execute - no exception
service.updateApp(newApp, true);
}
Aggregations