Skip to content

BI-2132 - Create new experiment workflow#366

Merged
nickpalladino merged 56 commits intodevelopfrom
feature/BI-2132-A
Jul 24, 2024
Merged

BI-2132 - Create new experiment workflow#366
nickpalladino merged 56 commits intodevelopfrom
feature/BI-2132-A

Conversation

@nickpalladino
Copy link
Member

@nickpalladino nickpalladino commented Jun 21, 2024

Description

Story: BI-2132

  • Workflow selection code (BI-2122) will be shown as changes in here until it is merged into develop

    • Review should focus on stuff from CreateNewExperimentWorkflow process down
    • However, there were a few changes from BI-2122 to pass exceptions up
  • Updated experiment import integration tests

    • Only updated tests that were related to creating experiments or environments
    • Tests that were updating based on obsunitid were not changed
  • Checked for ExperimentProcessor work done after refactor branched off develop

  • Workflow organization

    • Code common to the create and append/update workflows that depended on DAOs was broken out into Experiment services
    • A number of steps were defined in the create workflow package that correspond to the main steps in the experiment processor code. The main goal was just to remove use of member variables and explicitly pass data between methods for everything other than referenced services, daos, or properties.

Dependencies

Testing

Given I have navigated to the Experiment Import page
And I have selected the Create New Experiment option from the Workflows select box
And I have an experiment import file with values in the ObsUnitID column
When I click Upload
Then I should see an error notification Error detected in file: <filename>. ObsUnitIDs are detected. Import cannot proceed

Regression testing ideas:

Verify that appending a new environment to an experiment using the create new experiment workflow works

Verify that status updates on the jobs page work

Test different import file error conditions and verify they still occur as before

Checklist:

  • I have performed a self-review of my own code
  • I have tested my code and ensured it meets the acceptance criteria of the story
  • I have tested that my code works with both the brapi-java-server and BreedBase
  • I have create/modified unit tests to cover this change
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to documentation
  • I have run TAF: <please include a link to TAF run>

nickpalladino and others added 30 commits May 6, 2024 17:07
@nickpalladino nickpalladino requested review from a team, davedrp, dmeidlin and mlm483 and removed request for a team and davedrp June 21, 2024 20:50
@nickpalladino
Copy link
Member Author

nickpalladino commented Jun 21, 2024

TraitControllerIntegrationTest tests are failing with null program cache, seems like something is messed up with DI. Application stuff related to traits seems to work fine...

I'm seeing the same errors locally on develop but not in github actions. There was a failure in github actions but for something different:

Error: Failures:
Error: SampleSubmissionFileImportTest.importConflictingWellsFailure:389->uploadAndVerifyFailure:517 expected: <1> but was: <2>

Copy link
Contributor

@mlm483 mlm483 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor changes suggested, otherwise I approve.

@AllArgsConstructor
@NoArgsConstructor
public class ImportServiceContext {
private String workflow;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be more clear if this were renamed to workflowName? That way it would be clear that it's not the UUID converted to a string or something else.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about workflowId? It's called id in the Workflow enum in ExperimentWorkflowNavigator. May make sense to change that in the previous workflowName suggestion as well if you're good with it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickpalladino I think workflowId makes sense for the reason you said. WorkflowName is used for the display name. Also, see my comment in the UploadController about using workflowId there for consistency.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed changes

import java.util.List;
import java.util.Map;

// TODO: move to common higher level location
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this TODO mean?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified comment, let me know if that makes more sense

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, makes sense.

@ToString
@AllArgsConstructor
@NoArgsConstructor
public class PendingImportObjectData {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will anything analogous be needed for Germplasm?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could see doing something similar for other processors in the future to try and clean things up a bit but it's not required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, just wondering if the class name should be specific to experiment to prepare for that possibility.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be, it's already under the experiment package namespace so I guess it's a matter of preference. Could we leave it as-is until the point we may do some Germplasm or other processor work?

Comment on lines +94 to +107
public ProcessedData process(ProcessContext context, ProcessedPhenotypeData phenotypeData)
throws MissingRequiredInfoException, UnprocessableEntityException, ApiException {

Table data = context.getImportContext().getData();
ImportUpload upload = context.getImportContext().getUpload();
ImportContext importContext = context.getImportContext();

populatePendingImportObjects(context, phenotypeData);


// TODO: implement
return new ProcessedData();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the TODO to return data instead of mutating in-place? Or something else?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya, I'll clean up the interface and add some comments so it's clear what's actually happening

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed changes

Comment on lines +190 to +194
@ProgramSecured(roles = {ProgramSecuredRole.BREEDER, ProgramSecuredRole.SYSTEM_ADMIN})
public HttpResponse<Response<ImportResponse>> commitData(@PathVariable UUID programId, @PathVariable UUID mappingId,
@PathVariable String workflow, @PathVariable UUID uploadId,
@Body @Nullable Map<String, Object> userInput) {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing workflow to workflowId would be more consistent with the use here and with the enum.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed changes

Comment on lines +36 to 43
// TODO: delete processor fields once WorkflowNavigator is used
@Inject
public ExperimentImportService(Provider<ExperimentProcessor> experimentProcessorProvider, Provider<ProcessorManager> processorManagerProvider)
public ExperimentImportService(Provider<ExperimentProcessor> experimentProcessorProvider,
Provider<ProcessorManager> processorManagerProvider,
ExperimentWorkflowNavigator workflowNavigator)
{
this.experimentProcessorProvider = experimentProcessorProvider;
this.processorManagerProvider = processorManagerProvider;
super(experimentProcessorProvider, processorManagerProvider, workflowNavigator);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged into BI-2134 the changes from BI-2132 for ExperimentFileImportTest and was able to implement this TODO. So, there isn't any additional work required, you can just accept the changes during the merge.

Comment on lines +36 to +40

@Override
public List<ImportWorkflow> getWorkflows() throws Exception {
// Each workflow returns in the field workflow the metadata about the workflow that processed the import context.
// Loop over all workflows, processing a null context, to collect just the metadata
Copy link
Contributor

@dmeidlin dmeidlin Jul 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The throws Exception doesn't apply here since there isn't a scenario where getWorkflows() would ever pass up an exception from a lower level; it's only here because throws Exception was added to the Workflow#process signature. See my comments in BI-2134 on using the caughtException field instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The throws Exception was added there because ExperimentWorkflowNavigator::getWorkflows calls process on the ExperimentWorkflow and the process method in CreateNewExperimentWorkflow can throw exceptions. The particular code path for returning workflows wouldn't but the method in general can. I'll look at the BI-2134 stuff.

Comment on lines +186 to +194
public static void validateObservationValue(Trait variable, String value,
String columnHeader, ValidationErrors validationErrors, int row) {
if (StringUtils.isBlank(value)) {
log.debug(String.format("skipping validation of observation because there is no value.\n\tvariable: %s\n\trow: %d", variable.getObservationVariableName(), row));
return;
}

if (isNAObservation(value)) {
log.debug(String.format("skipping validation of observation because it is NA.\n\tvariable: %s\n\trow: %d", variable.getObservationVariableName(), row));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In BI-2134, I put these validations into instances of the ObservationValidator functional interface with FieldValidator acting as the primary. The package is at the service level, so it can be used for both workflows.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a card BI-2230 to do cleanup and reduce code duplication between workflows to limit the scope of changes in this PR.

Comment on lines +174 to +175
// TODO: unify usage of single import context type throughout
ImportContext importContext = ImportContext.from(context);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. I suggest for ImportServiceContext renaming workflow to workflowId, brapiImports to importRows, and adding the Map<Integer, PendingImport> mappedBrAPIImport field. Then eliminating the ImportContext class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a card BI-2230 to do cleanup and reduce code duplication between workflows to limit the scope of changes in this PR.

Comment on lines +160 to +168
newExperimentWorkflowId = getNewExperimentWorkflowId();
}

/**
* TODO: assumes new workflow is first in list, doesn't look at position property, would be more robust to
* look at that instead of assuming order
* @return
*/
public String getNewExperimentWorkflowId() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've merged this into BI-2134 and renamed to ExperimentFileImportTest#getExperimentWorkflowId with an integer argument for selecting the workflow id from the list fetched by getWorkflows().

Comment on lines +178 to +184
// Start processing the import...
ImportPreviewResponse response = runWorkflow(importContext);

result = Optional.of(ImportWorkflowResult.builder()
.workflow(workflow)
.importPreviewResponse(Optional.of(response))
.build());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When merging with BI-2134, just wrap the runWorkflow() call in a try-catch as below, and any exceptions will be passed and handled by the higher levels as usual. No other changes are needed.

Suggested change
// Start processing the import...
ImportPreviewResponse response = runWorkflow(importContext);
result = Optional.of(ImportWorkflowResult.builder()
.workflow(workflow)
.importPreviewResponse(Optional.of(response))
.build());
// Start processing the import...
try {
ImportPreviewResponse successResponse;
successResponse = runWorkflow(importContext);
result.ifPresent(importWorkflowResult -> importWorkflowResult.setImportPreviewResponse(Optional.of(successResponse)));
} catch (Exception e) {
result.ifPresent(importWorkflowResult -> importWorkflowResult.setCaughtException(Optional.of(e)));
}
return result;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, just about have it done. Need to remove Exception stuff on method signatures.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed changes

@nickpalladino nickpalladino requested a review from dmeidlin July 2, 2024 20:34
@nickpalladino nickpalladino merged commit c9ed7d0 into develop Jul 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants