diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000000..003aa9d99fa
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000000..6e6eec11483
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/prime-router/src/main/kotlin/azure/DatabaseAccess.kt b/prime-router/src/main/kotlin/azure/DatabaseAccess.kt
index d72c1b4eba2..e293e6cdfa2 100644
--- a/prime-router/src/main/kotlin/azure/DatabaseAccess.kt
+++ b/prime-router/src/main/kotlin/azure/DatabaseAccess.kt
@@ -407,8 +407,8 @@ class DatabaseAccess(val create: DSLContext) : Logging {
txn: DataAccessTransaction? = null,
): CovidResultMetadata? {
val ctx = if (txn != null) DSL.using(txn) else create
- return ctx.selectFrom(Tables.COVID_RESULT_METADATA)
- .where(Tables.COVID_RESULT_METADATA.MESSAGE_ID.eq(messageID.toString()))
+ return ctx.selectFrom(COVID_RESULT_METADATA)
+ .where(COVID_RESULT_METADATA.MESSAGE_ID.eq(messageID.toString()))
.fetchOne()
?.into(CovidResultMetadata::class.java)
}
@@ -476,11 +476,11 @@ class DatabaseAccess(val create: DSLContext) : Logging {
): List {
val ctx = if (txn != null) DSL.using(txn) else create
return ctx
- .selectFrom(Tables.ACTION_LOG)
+ .selectFrom(ACTION_LOG)
.where(
- Tables.ACTION_LOG.REPORT_ID.eq(reportId)
- .and(Tables.ACTION_LOG.TRACKING_ID.eq(trackingId))
- .and(Tables.ACTION_LOG.TYPE.eq(type))
+ ACTION_LOG.REPORT_ID.eq(reportId)
+ .and(ACTION_LOG.TRACKING_ID.eq(trackingId))
+ .and(ACTION_LOG.TYPE.eq(type))
)
.limit(100)
.fetchInto(DetailedActionLog::class.java)
@@ -1280,8 +1280,8 @@ class DatabaseAccess(val create: DSLContext) : Logging {
// todo: migrate away from the covid test data which is legacy
// we are going to have a more generic full elr table that we want to use
// instead, but for now we need to maintain the older covid result metadata table
- DatabaseAccess.saveTestData(actionHistory.elrMetaDataRecords, txn)
- DatabaseAccess.saveCovidTestData(actionHistory.covidResultMetadataRecords, txn)
+ saveTestData(actionHistory.elrMetaDataRecords, txn)
+ saveCovidTestData(actionHistory.covidResultMetadataRecords, txn)
// generate lineage records
actionHistory.generateLineages()
@@ -1347,8 +1347,8 @@ class DatabaseAccess(val create: DSLContext) : Logging {
/**
* Inserts the provided [actionLog] using [txn] as the data context.
*/
- private fun insertActionLog(actionLog: ActionLog, txn: Configuration) {
- val detailRecord = DSL.using(txn).newRecord(Tables.ACTION_LOG, actionLog)
+ fun insertActionLog(actionLog: ActionLog, txn: Configuration) {
+ val detailRecord = DSL.using(txn).newRecord(ACTION_LOG, actionLog)
detailRecord.store()
}
diff --git a/prime-router/src/main/kotlin/azure/ReportFunction.kt b/prime-router/src/main/kotlin/azure/ReportFunction.kt
index 70fc5aabed4..24c535ed849 100644
--- a/prime-router/src/main/kotlin/azure/ReportFunction.kt
+++ b/prime-router/src/main/kotlin/azure/ReportFunction.kt
@@ -225,7 +225,9 @@ class ReportFunction(
workflowEngine.recordAction(actionHistory)
check(actionHistory.action.actionId > 0)
- val submission = SubmissionsFacade.instance.findDetailedSubmissionHistory(actionHistory.action)
+ val submission = workflowEngine.db.transactReturning { txn ->
+ SubmissionsFacade.instance.findDetailedSubmissionHistory(txn, null, actionHistory.action)
+ }
val response = request.createResponseBuilder(httpStatus)
.header(HttpHeaders.CONTENT_TYPE, "application/json")
@@ -236,7 +238,7 @@ class ReportFunction(
.header(
HttpHeaders.LOCATION,
request.uri.resolve(
- "/api/history/${sender.organizationName}/submissions/${actionHistory.action.actionId}"
+ "/api/waters/report/${submission?.reportId}/history"
).toString()
)
.build()
diff --git a/prime-router/src/main/kotlin/history/ReportHistory.kt b/prime-router/src/main/kotlin/history/ReportHistory.kt
index cd5bc2c0d2f..4d187c5398a 100644
--- a/prime-router/src/main/kotlin/history/ReportHistory.kt
+++ b/prime-router/src/main/kotlin/history/ReportHistory.kt
@@ -11,6 +11,7 @@ import gov.cdc.prime.router.ActionLogScope
import gov.cdc.prime.router.ErrorCode
import gov.cdc.prime.router.ItemActionLogDetail
import gov.cdc.prime.router.Topic
+import gov.cdc.prime.router.azure.db.enums.TaskAction
import java.time.OffsetDateTime
import java.util.UUID
@@ -77,6 +78,12 @@ data class DetailedReport(
val itemCountBeforeQualFilter: Int?,
@JsonIgnore
val receiverHasTransport: Boolean,
+ @JsonIgnore
+ val transportResult: String?,
+ @JsonIgnore
+ val downloadedBy: String?,
+ @JsonIgnore
+ val nextAction: TaskAction?,
)
/**
diff --git a/prime-router/src/main/kotlin/history/SubmissionHistory.kt b/prime-router/src/main/kotlin/history/SubmissionHistory.kt
index cc6f6134f37..15f7af3aaee 100644
--- a/prime-router/src/main/kotlin/history/SubmissionHistory.kt
+++ b/prime-router/src/main/kotlin/history/SubmissionHistory.kt
@@ -12,7 +12,6 @@ import gov.cdc.prime.router.ActionLogLevel
import gov.cdc.prime.router.ActionLogScope
import gov.cdc.prime.router.ClientSource
import gov.cdc.prime.router.ReportStreamFilterResult
-import gov.cdc.prime.router.Sender
import gov.cdc.prime.router.Topic
import gov.cdc.prime.router.azure.db.enums.TaskAction
import gov.cdc.prime.router.common.BaseEngine
@@ -120,9 +119,9 @@ class DetailedSubmissionHistory(
createdAt: OffsetDateTime,
httpStatus: Int? = null,
@JsonIgnore
- val reports: MutableList? = mutableListOf(),
+ val reports: List,
@JsonIgnore
- var logs: List = emptyList(),
+ var logs: List,
) : SubmissionHistory(
actionId,
createdAt,
@@ -240,9 +239,13 @@ class DetailedSubmissionHistory(
}
init {
- reports?.forEach { report ->
- // For reports sent to a destination
- report.receivingOrg?.let {
+ // Iterate over all the reports in the report lineage, processing them to generate the
+ // destinations
+ reports.forEach { report ->
+
+ // If the report has a receiving org, it means that it contains information about a destination
+ report.receivingOrg?.apply {
+
val filterLogs = logs.filter {
it.type == ActionLogLevel.filter && it.reportId == report.reportId
}
@@ -250,26 +253,40 @@ class DetailedSubmissionHistory(
val filteredReportItems = filterLogs.map {
ReportStreamFilterResultForResponse(it.detail as ReportStreamFilterResult)
}
- // If there is no transport defined, there will not be a next action so sending at
- // should be null.
- val nextActionTime = if (report.receiverHasTransport) report.nextActionAt else null
- destinations.add(
- Destination(
- report.receivingOrg,
- report.receivingOrgSvc!!,
- filteredReportRows.toMutableList(),
- filteredReportItems.toMutableList(),
- nextActionTime,
- report.itemCount,
- report.itemCountBeforeQualFilter,
+
+ val existingDestination =
+ destinations.find {
+ it.organizationId == report.receivingOrg && it.service == report.receivingOrgSvc
+ }
+ val sentReports = if (report.transportResult != null) mutableListOf(report) else mutableListOf()
+ val downloadedReports = if (report.downloadedBy != null) mutableListOf(report) else mutableListOf()
+
+ if (existingDestination == null) {
+
+ destinations.add(
+ Destination(
+ report.receivingOrg,
+ report.receivingOrgSvc!!,
+ filteredReportRows.toMutableList(),
+ filteredReportItems.toMutableList(),
+ report.nextActionAt,
+ report.itemCount,
+ report.itemCountBeforeQualFilter,
+ sentReports = sentReports,
+ downloadedReports
+ )
)
- )
+ } else {
+ existingDestination.sentReports.addAll(sentReports)
+ existingDestination.downloadedReports.addAll(downloadedReports)
+ if (report.nextActionAt != null) {
+ existingDestination.sendingAt = report.nextActionAt
+ }
+ }
}
// For the report received from a sender
if (report.sendingOrg != null) {
- // There can only be one!
- check(reportId == null)
// Reports with errors do not show an ID
reportId = if (errorCount == 0) report.reportId.toString() else null
externalName = report.externalName
@@ -277,10 +294,20 @@ class DetailedSubmissionHistory(
sender = ClientSource(report.sendingOrg, report.sendingOrgClient ?: "").name
topic = report.schemaTopic
}
-
// if there is ANY action scheduled on this submission history, ensure this flag is true
if (report.nextActionAt != null) nextActionScheduled = true
}
+ destinations.forEach { destination ->
+ val reportsForDestination = reports.filter {
+ destination.organizationId == it.receivingOrg && destination.service == it.receivingOrgSvc
+ }.sortedBy { it.createdAt }
+ val latestAction = reportsForDestination.first().nextAction
+ val reportsGroupedByLatestAction = reportsForDestination.groupBy { it.nextAction }
+ val mostRecentReportsForDestination = reportsGroupedByLatestAction[latestAction] ?: emptyList()
+ destination.itemCount = mostRecentReportsForDestination.sumOf { it.itemCount }
+ destination.itemCountBeforeQualFilter =
+ mostRecentReportsForDestination.sumOf { it.itemCountBeforeQualFilter ?: 0 }
+ }
errors.addAll(consolidateLogs(ActionLogLevel.error))
warnings.addAll(consolidateLogs(ActionLogLevel.warning))
}
@@ -325,240 +352,6 @@ class DetailedSubmissionHistory(
return consolidatedList
}
- // TODO: https://github.com/CDCgov/prime-reportstream/issues/14350
- /**
- * Enrich the submission history with various other related bits of history.
- *
- * @param descendants[] the various bits of DetailedSubmissionHistory that will be used to enrich
- */
- fun enrichWithDescendants(descendants: List) {
- check(descendants.distinctBy { it.actionId }.size == descendants.size)
- actionsPerformed.addAll(descendants.map { submission -> submission.actionName }.distinct())
-
- // Enforce an order on the enrichment: process/translate, send, download
- if (topic?.isUniversalPipeline == true) {
- // logs and destinations are handled very differently for UP
- // both routing and translate are populated at different times,
- // so we need to do special logic to handle them
- descendants.filter { it.actionName == TaskAction.translate }.forEach { descendant ->
- enrichWithTranslateAction(descendant)
- }
- descendants.filter { it.actionName == TaskAction.route }.forEach { descendant ->
- enrichWithRouteAction(descendant)
- }
- descendants.filter { it.actionName == TaskAction.convert }.forEach { descendant ->
- enrichWithConvertAction(descendant)
- }
- } else {
- descendants.filter {
- it.actionName == TaskAction.process
- }.forEach { descendant ->
- enrichWithProcessAction(descendant)
- }
- }
-
- // note: we do not use any data from the batch action at this time.
- descendants.filter { it.actionName == TaskAction.send }.forEach { descendant ->
- enrichWithSendAction(descendant)
- }
- descendants.filter { it.actionName == TaskAction.download }.forEach { descendant ->
- enrichWithDownloadAction(descendant)
- }
- }
-
- /**
- * Enrich a parent detailed history with details from translate actions.
- * Add destinations, errors, and warnings, to the history details.
- * Note: Route/Translate is exclusive to the Universal pipeline
- * See enrichWithProcessAction for the TopicReceiver pipeline counterpart
- *
- * @param descendant translate action that will be used to enrich
- */
- private fun enrichWithTranslateAction(descendant: DetailedSubmissionHistory) {
- require(
- topic?.isUniversalPipeline == true &&
- descendant.actionName == TaskAction.translate
- ) {
- "Must be translate action. Enrichment is only available for the Universal Pipeline"
- }
-
- // Grab destinations from the "translate" action
- descendant.destinations.forEach { descendantDest ->
- // Check if destination has already been added
- // if it is increase item counts
- // otherwise add it to destinations
- destinations.firstOrNull {
- it.organizationId == descendantDest.organizationId && it.service == descendantDest.service
- }?.let { existingDestination ->
- existingDestination.itemCount += descendantDest.itemCount
- existingDestination.itemCountBeforeQualFilter =
- existingDestination.itemCountBeforeQualFilter?.plus(
- descendantDest.itemCountBeforeQualFilter ?: 0
- ) ?: descendantDest.itemCountBeforeQualFilter
- } ?: run {
- destinations += descendantDest
- }
- }
- }
-
- /**
- * Enrich a parent detailed history with details from the convert action.
- * Add errors, and warnings, to the history details.
- *
- * @param descendant route action that will be used to enrich
- */
- private fun enrichWithConvertAction(descendant: DetailedSubmissionHistory) {
- require(
- topic?.isUniversalPipeline == true &&
- descendant.actionName == TaskAction.convert
- ) {
- "Must be route action. Enrichment is only available for the Universal Pipeline"
- }
- errors += descendant.errors
- warnings += descendant.warnings
- }
-
- /**
- * Enrich a parent detailed history with details from the route action.
- * Add destinations, errors, and warnings, to the history details.
- * Note: Route/Translate is exclusive to the Universal pipeline
- * See enrichWithProcessAction for the TopicReceiver pipeline counterpart
- *
- * @param descendant route action that will be used to enrich
- */
- private fun enrichWithRouteAction(descendant: DetailedSubmissionHistory) {
- require(
- topic?.isUniversalPipeline == true &&
- descendant.actionName == TaskAction.route
- ) {
- "Must be route action. Enrichment is only available for the Universal Pipeline"
- }
- // Grab the filter logs generated during the "route" action, as well as errors and warnings
- val filterLogs = descendant.logs.filter { log -> log.type == ActionLogLevel.filter }
- errors += descendant.errors
- warnings += descendant.warnings
-
- // add filter logs to its respective destination otherwise add new destination
- if (filterLogs.isNotEmpty()) {
- filterLogs.forEach { log ->
- check(log.detail is ReportStreamFilterResult) { "Filter result not of type ReportStreamFilterResult" }
- val filterResult = log.detail
- val filterReport = log.detail.message
- val receiverNameSegments = filterResult.receiverName.split(Sender.fullNameSeparator)
- val filterResultResponse = ReportStreamFilterResultForResponse(filterResult)
-
- destinations.firstOrNull {
- it.organizationId == receiverNameSegments[0] && it.service == receiverNameSegments[1]
- }?.let { existingDestination ->
- // filteredReportRows and filteredReportItems are initialized
- // when a DetailedSubmissionHistory is created, so they shouldn't be null
- existingDestination.filteredReportRows!!.add(filterReport)
- existingDestination.filteredReportItems!!.add(filterResultResponse)
- existingDestination.itemCountBeforeQualFilter = existingDestination.itemCountBeforeQualFilter?.plus(
- filterResult.originalCount
- ) ?: filterResult.originalCount
- } ?: run {
- destinations.add(
- Destination(
- receiverNameSegments[0],
- receiverNameSegments[1],
- mutableListOf(filterReport),
- mutableListOf(ReportStreamFilterResultForResponse(filterResult)),
- null,
- 0,
- filterResult.originalCount,
- )
- )
- }
- }
- }
- }
-
- /**
- * Enrich a parent detailed history with details from the process action.
- * Add destinations, errors, and warnings, to the history details.
- * Note: Process is exclusive to the COVID pipeline
- * See enrichWithRoutingAndTranslationActions for the Universal pipeline counterpart
- *
- * @param descendant the history used for enriching
- */
- private fun enrichWithProcessAction(descendant: DetailedSubmissionHistory) {
- require(descendant.actionName == TaskAction.process) {
- "Must be a process action"
- }
- destinations += descendant.destinations
- errors += descendant.errors
- warnings += descendant.warnings
- }
-
- /**
- * Enrich a parent detailed history with details from the send action.
- * Add sent report information to each destination present in the parent's historical details.
- *
- * @param descendant the history used for enriching
- */
- private fun enrichWithSendAction(descendant: DetailedSubmissionHistory) {
- require(descendant.actionName == TaskAction.send) { "Must be a send action" }
- descendant.reports?.let { it ->
- it.forEach { report ->
- destinations.find {
- it.organizationId == report.receivingOrg && it.service == report.receivingOrgSvc
- }?.let {
- it.sentReports.add(report)
- } ?: run {
- if (report.receivingOrg != null && report.receivingOrgSvc != null) {
- destinations.add(
- Destination(
- report.receivingOrg,
- report.receivingOrgSvc,
- null,
- null,
- null,
- report.itemCount,
- report.itemCountBeforeQualFilter,
- )
- )
- }
- }
- }
- }
- }
-
- /**
- * Enrich a parent detailed history with details from the download action
- * Add download report information to each destination present in the parent's historical details.
- *
- * @param descendant the history used for enriching
- */
- private fun enrichWithDownloadAction(descendant: DetailedSubmissionHistory) {
- require(descendant.actionName == TaskAction.download) { "Must be a download action" }
-
- descendant.reports?.let { it ->
- it.forEach { report ->
- destinations.find {
- it.organizationId == report.receivingOrg && it.service == report.receivingOrgSvc
- }?.let {
- it.downloadedReports.add(report)
- } ?: run {
- if (report.receivingOrg != null && report.receivingOrgSvc != null) {
- val dest = Destination(
- report.receivingOrg,
- report.receivingOrgSvc,
- null,
- null,
- null,
- report.itemCount,
- report.itemCountBeforeQualFilter,
- )
-
- destinations.add(dest)
- dest.downloadedReports.add(report)
- }
- }
- }
- }
- }
-
/**
* Update the summary fields for this Submission report based on the destinations that
* will be receiving reports.
@@ -591,8 +384,7 @@ class DetailedSubmissionHistory(
* the receivers.
*/
return if (
- (actionsPerformed.contains(TaskAction.route) || actionsPerformed.contains(TaskAction.convert)) &&
- !nextActionScheduled
+ reports.size > 1
) {
Status.NOT_DELIVERING
} else {
@@ -703,7 +495,7 @@ data class Destination(
val filteredReportItems: MutableList?,
@JsonProperty("sending_at")
@JsonInclude(Include.NON_NULL)
- val sendingAt: OffsetDateTime?,
+ var sendingAt: OffsetDateTime?,
var itemCount: Int,
@JsonProperty("itemCountBeforeQualityFiltering")
var itemCountBeforeQualFilter: Int?,
diff --git a/prime-router/src/main/kotlin/history/azure/DeliveryFunction.kt b/prime-router/src/main/kotlin/history/azure/DeliveryFunction.kt
index a543668519c..b63ab240924 100644
--- a/prime-router/src/main/kotlin/history/azure/DeliveryFunction.kt
+++ b/prime-router/src/main/kotlin/history/azure/DeliveryFunction.kt
@@ -12,6 +12,7 @@ import com.microsoft.azure.functions.annotation.HttpTrigger
import gov.cdc.prime.router.CustomerStatus
import gov.cdc.prime.router.Sender
import gov.cdc.prime.router.azure.ApiResponse
+import gov.cdc.prime.router.azure.DataAccessTransaction
import gov.cdc.prime.router.azure.HttpUtilities
import gov.cdc.prime.router.azure.WorkflowEngine
import gov.cdc.prime.router.azure.db.enums.TaskAction
@@ -165,7 +166,7 @@ class DeliveryFunction(
* @param action Action from which the data for the delivery is loaded
* @return
*/
- override fun singleDetailedHistory(queryParams: MutableMap, action: Action): DeliveryHistory? {
+ override fun singleDetailedHistory(id: String, txn: DataAccessTransaction, action: Action): DeliveryHistory? {
return deliveryFacade.findDetailedDeliveryHistory(action.actionId)
}
diff --git a/prime-router/src/main/kotlin/history/azure/ReportFileFacade.kt b/prime-router/src/main/kotlin/history/azure/ReportFileFacade.kt
index b3cef09c691..e95a6e2319d 100644
--- a/prime-router/src/main/kotlin/history/azure/ReportFileFacade.kt
+++ b/prime-router/src/main/kotlin/history/azure/ReportFileFacade.kt
@@ -1,6 +1,7 @@
package gov.cdc.prime.router.history.azure
import com.microsoft.azure.functions.HttpRequestMessage
+import gov.cdc.prime.router.azure.DataAccessTransaction
import gov.cdc.prime.router.azure.DatabaseAccess
import gov.cdc.prime.router.azure.db.tables.pojos.Action
import gov.cdc.prime.router.azure.db.tables.pojos.ReportFile
@@ -26,8 +27,8 @@ abstract class ReportFileFacade(
/**
* @return a single Report associated with this [actionId]
*/
- fun fetchReportForActionId(actionId: Long): ReportFile? {
- return dbAccess.fetchReportForActionId(actionId)
+ fun fetchReportForActionId(actionId: Long, txn: DataAccessTransaction? = null): ReportFile? {
+ return dbAccess.fetchReportForActionId(actionId, txn)
}
/**
diff --git a/prime-router/src/main/kotlin/history/azure/ReportFileFunction.kt b/prime-router/src/main/kotlin/history/azure/ReportFileFunction.kt
index 35e978f6ffc..cf88c750881 100644
--- a/prime-router/src/main/kotlin/history/azure/ReportFileFunction.kt
+++ b/prime-router/src/main/kotlin/history/azure/ReportFileFunction.kt
@@ -6,6 +6,7 @@ import com.microsoft.azure.functions.HttpResponseMessage
import com.microsoft.azure.functions.HttpStatus
import gov.cdc.prime.router.CustomerStatus
import gov.cdc.prime.router.RESTTransportType
+import gov.cdc.prime.router.azure.DataAccessTransaction
import gov.cdc.prime.router.azure.HttpUtilities
import gov.cdc.prime.router.azure.WorkflowEngine
import gov.cdc.prime.router.azure.db.tables.pojos.Action
@@ -75,7 +76,7 @@ abstract class ReportFileFunction(
* @param action Action from which the data for the report is loaded
* @return
*/
- abstract fun singleDetailedHistory(queryParams: MutableMap, action: Action): ReportHistory?
+ abstract fun singleDetailedHistory(id: String, txn: DataAccessTransaction, action: Action): ReportHistory?
/**
* Verify that the action being checked has the correct data/parameters
@@ -152,13 +153,10 @@ abstract class ReportFileFunction(
authResult
} else {
val action = this.actionFromId(id)
- val history = this.singleDetailedHistory(request.queryParameters, action)
-
- if (history != null) {
- HttpUtilities.okJSONResponse(request, history)
- } else {
- HttpUtilities.notFoundResponse(request, "History entry ${action.actionId} was not found.")
+ val history = workflowEngine.db.transactReturning { txn ->
+ this.singleDetailedHistory(id, txn, action)
}
+ HttpUtilities.okJSONResponse(request, history)
}
} catch (e: DataAccessException) {
logger.error("Unable to fetch history for ID $id", e)
diff --git a/prime-router/src/main/kotlin/history/azure/SubmissionFunction.kt b/prime-router/src/main/kotlin/history/azure/SubmissionFunction.kt
index 7fd7c8687ca..c63d1dcdb18 100644
--- a/prime-router/src/main/kotlin/history/azure/SubmissionFunction.kt
+++ b/prime-router/src/main/kotlin/history/azure/SubmissionFunction.kt
@@ -9,6 +9,7 @@ import com.microsoft.azure.functions.annotation.BindingName
import com.microsoft.azure.functions.annotation.FunctionName
import com.microsoft.azure.functions.annotation.HttpTrigger
import gov.cdc.prime.router.Sender
+import gov.cdc.prime.router.azure.DataAccessTransaction
import gov.cdc.prime.router.azure.WorkflowEngine
import gov.cdc.prime.router.azure.db.enums.TaskAction
import gov.cdc.prime.router.azure.db.tables.pojos.Action
@@ -91,10 +92,20 @@ class SubmissionFunction(
* @return
*/
override fun singleDetailedHistory(
- queryParams: MutableMap,
+ id: String,
+ txn: DataAccessTransaction,
action: Action,
): DetailedSubmissionHistory? {
- return submissionsFacade.findDetailedSubmissionHistory(action)
+ val report = try {
+ val reportId = UUID.fromString(id)
+ submissionsFacade.findDetailedSubmissionHistory(txn, reportId, action)
+ } catch (ex: IllegalArgumentException) {
+ // We cannot consistently use this logic because the covid pipeline can process reports
+ // synchronously such that the intial action has multiple reports associated (i.e. receive and send)
+ val report = submissionsFacade.fetchReportForActionId(action.actionId, txn)
+ submissionsFacade.findDetailedSubmissionHistory(txn, report?.reportId, action)
+ }
+ return report
}
/**
diff --git a/prime-router/src/main/kotlin/history/azure/SubmissionsFacade.kt b/prime-router/src/main/kotlin/history/azure/SubmissionsFacade.kt
index 116754549bd..d83a1bd7918 100644
--- a/prime-router/src/main/kotlin/history/azure/SubmissionsFacade.kt
+++ b/prime-router/src/main/kotlin/history/azure/SubmissionsFacade.kt
@@ -1,14 +1,19 @@
package gov.cdc.prime.router.history.azure
import com.microsoft.azure.functions.HttpRequestMessage
+import gov.cdc.prime.router.azure.DataAccessTransaction
import gov.cdc.prime.router.azure.DatabaseAccess
-import gov.cdc.prime.router.azure.db.enums.TaskAction
+import gov.cdc.prime.router.azure.db.Tables
import gov.cdc.prime.router.azure.db.tables.pojos.Action
import gov.cdc.prime.router.common.BaseEngine
import gov.cdc.prime.router.common.JacksonMapperUtilities
+import gov.cdc.prime.router.history.DetailedActionLog
+import gov.cdc.prime.router.history.DetailedReport
import gov.cdc.prime.router.history.DetailedSubmissionHistory
import gov.cdc.prime.router.history.SubmissionHistory
+import gov.cdc.prime.router.history.db.ReportGraph
import gov.cdc.prime.router.tokens.AuthenticatedClaims
+import org.jooq.impl.DSL
import java.time.OffsetDateTime
import java.util.UUID
@@ -18,7 +23,8 @@ import java.util.UUID
*/
class SubmissionsFacade(
private val dbSubmissionAccess: HistoryDatabaseAccess = DatabaseSubmissionsAccess(),
- dbAccess: DatabaseAccess = BaseEngine.databaseAccessSingleton,
+ val dbAccess: DatabaseAccess = BaseEngine.databaseAccessSingleton,
+ private val reportGraph: ReportGraph = ReportGraph(),
) : ReportFileFacade(
dbAccess,
) {
@@ -116,30 +122,56 @@ class SubmissionsFacade(
* @return Report details
*/
fun findDetailedSubmissionHistory(
+ txn: DataAccessTransaction,
+ reportId: UUID?,
action: Action,
): DetailedSubmissionHistory? {
- // This assumes that ReportFileFunction.authSingleBlocks has already run, and has checked that the
- // sendingOrg is good. If that assumption is incorrect, die here.
- assert(action.sendingOrg != null && action.actionName == TaskAction.receive)
- val submission = dbSubmissionAccess.fetchAction(
- action.actionId,
- action.sendingOrg,
- DetailedSubmissionHistory::class.java
- )
- submission?.actionsPerformed?.add(action.actionName)
-
- // Submissions with a report ID (means had no errors) can have a lineage
- submission?.reportId?.let {
- val relatedSubmissions = dbSubmissionAccess.fetchRelatedActions(
- UUID.fromString(it),
+ if (reportId == null) {
+ return dbSubmissionAccess.fetchAction(
+ action.actionId,
+ action.sendingOrg,
DetailedSubmissionHistory::class.java
)
- submission.enrichWithDescendants(relatedSubmissions)
}
+ val graph = reportGraph.getDescendantReports(txn, reportId)
+ val detailedReports = graph.map { reportFile ->
+ DetailedReport(
+ reportFile.reportId,
+ reportFile.receivingOrg,
+ reportFile.receivingOrgSvc,
+ reportFile.sendingOrg,
+ reportFile.sendingOrgClient,
+ reportFile.schemaTopic,
+ reportFile.externalName,
+ reportFile.createdAt,
+ reportFile.nextActionAt,
+ reportFile.itemCount,
+ reportFile.itemCountBeforeQualFilter,
+ reportFile.transportResult != null,
+ reportFile.transportResult,
+ reportFile.downloadedBy,
+ reportFile.nextAction
+ )
+ }.toMutableList()
+ val reportIds = graph.map { it.reportId }
+ val logs = DSL
+ .using(txn)
+ .select()
+ .from(Tables.ACTION_LOG)
+ .where(Tables.ACTION_LOG.REPORT_ID.`in`(reportIds))
+ .fetchInto(DetailedActionLog::class.java)
+ val history =
+ DetailedSubmissionHistory(
+ action.actionId,
+ action.actionName,
+ action.createdAt,
+ httpStatus = action.httpStatus,
+ logs = logs,
+ reports = detailedReports
- submission?.enrichWithSummary()
-
- return submission
+ )
+ history.enrichWithSummary()
+ return history
}
/**
diff --git a/prime-router/src/main/kotlin/history/db/ReportGraph.kt b/prime-router/src/main/kotlin/history/db/ReportGraph.kt
index afddbb1d341..910b837af1b 100644
--- a/prime-router/src/main/kotlin/history/db/ReportGraph.kt
+++ b/prime-router/src/main/kotlin/history/db/ReportGraph.kt
@@ -17,8 +17,10 @@ import gov.cdc.prime.router.common.BaseEngine
import org.apache.logging.log4j.kotlin.Logging
import org.jooq.CommonTableExpression
import org.jooq.DSLContext
+import org.jooq.Record
import org.jooq.Record1
import org.jooq.Record2
+import org.jooq.SelectOnConditionStep
import org.jooq.impl.CustomRecord
import org.jooq.impl.CustomTable
import org.jooq.impl.DSL
@@ -157,7 +159,7 @@ class ReportGraph(
fun getDescendantReports(
txn: DataAccessTransaction,
parentReportId: UUID,
- searchedForTaskActions: Set,
+ searchedForTaskActions: Set? = null,
): List {
val cte = reportDescendantGraphCommonTableExpression(listOf(parentReportId))
return descendantReportRecords(txn, cte, searchedForTaskActions).fetchInto(ReportFile::class.java)
@@ -408,15 +410,22 @@ class ReportGraph(
private fun descendantReportRecords(
txn: DataAccessTransaction,
cte: CommonTableExpression>,
- searchedForTaskActions: Set,
- ) = DSL.using(txn)
- .withRecursive(cte)
- .select(REPORT_FILE.asterisk())
- .distinctOn(REPORT_FILE.REPORT_ID)
- .from(cte)
- .join(REPORT_FILE)
- .on(REPORT_FILE.REPORT_ID.eq(cte.field(0, UUID::class.java)))
- .join(ACTION)
- .on(ACTION.ACTION_ID.eq(REPORT_FILE.ACTION_ID))
- .where(ACTION.ACTION_NAME.`in`(searchedForTaskActions))
+ searchedForTaskActions: Set?,
+ ): SelectOnConditionStep {
+ val select = DSL.using(txn)
+ .withRecursive(cte)
+ .select(REPORT_FILE.asterisk())
+ .distinctOn(REPORT_FILE.REPORT_ID)
+ .from(cte)
+ .join(REPORT_FILE)
+ .on(REPORT_FILE.REPORT_ID.eq(cte.field(0, UUID::class.java)))
+ .join(ACTION)
+ .on(ACTION.ACTION_ID.eq(REPORT_FILE.ACTION_ID))
+
+ if (searchedForTaskActions != null) {
+ select.where(ACTION.ACTION_NAME.`in`(searchedForTaskActions))
+ }
+
+ return select
+ }
}
\ No newline at end of file
diff --git a/prime-router/src/test/kotlin/azure/HttpTestUtils.kt b/prime-router/src/test/kotlin/azure/HttpTestUtils.kt
index 8b4604943f2..b171a3763bb 100644
--- a/prime-router/src/test/kotlin/azure/HttpTestUtils.kt
+++ b/prime-router/src/test/kotlin/azure/HttpTestUtils.kt
@@ -15,13 +15,14 @@ import kotlin.collections.Map
class MockHttpResponseMessage : HttpResponseMessage.Builder, HttpResponseMessage {
var httpStatus: HttpStatusType = HttpStatus.OK
var content: Any? = null
+ var headers: MutableMap = mutableMapOf()
override fun getStatus(): HttpStatusType {
return this.httpStatus
}
override fun getHeader(var1: String): String {
- return "world"
+ return headers.getOrDefault(var1, "world")
}
override fun getBody(): Any? {
@@ -34,6 +35,7 @@ class MockHttpResponseMessage : HttpResponseMessage.Builder, HttpResponseMessage
}
override fun header(key: String, value: String): HttpResponseMessage.Builder {
+ headers[key] = value
return this
}
diff --git a/prime-router/src/test/kotlin/azure/ReportFunctionTests.kt b/prime-router/src/test/kotlin/azure/ReportFunctionTests.kt
index e37a252cd38..e08577b2ad4 100644
--- a/prime-router/src/test/kotlin/azure/ReportFunctionTests.kt
+++ b/prime-router/src/test/kotlin/azure/ReportFunctionTests.kt
@@ -1,5 +1,8 @@
package gov.cdc.prime.router.azure
+import assertk.assertThat
+import assertk.assertions.isEqualTo
+import com.google.common.net.HttpHeaders
import com.microsoft.azure.functions.HttpStatus
import gov.cdc.prime.router.ActionLog
import gov.cdc.prime.router.ClientSource
@@ -21,12 +24,15 @@ import gov.cdc.prime.router.Topic
import gov.cdc.prime.router.TopicReceiver
import gov.cdc.prime.router.UniversalPipelineSender
import gov.cdc.prime.router.azure.db.enums.TaskAction
+import gov.cdc.prime.router.history.DetailedSubmissionHistory
+import gov.cdc.prime.router.history.azure.SubmissionsFacade
import gov.cdc.prime.router.serializers.Hl7Serializer
import gov.cdc.prime.router.tokens.AuthenticatedClaims
import gov.cdc.prime.router.tokens.AuthenticationType
import gov.cdc.prime.router.unittest.UnitTestUtils
import io.mockk.clearAllMocks
import io.mockk.every
+import io.mockk.mockk
import io.mockk.mockkClass
import io.mockk.mockkObject
import io.mockk.spyk
@@ -37,6 +43,8 @@ import org.jooq.tools.jdbc.MockResult
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
+import java.time.OffsetDateTime
+import java.util.UUID
class ReportFunctionTests {
val dataProvider = MockDataProvider { emptyArray() }
@@ -585,6 +593,20 @@ class ReportFunctionTests {
every { accessSpy.isDuplicateItem(any(), any()) } returns false
+ val mockSubmissionsFacade = mockk()
+ mockkObject(SubmissionsFacade)
+ every { SubmissionsFacade.instance } returns mockSubmissionsFacade
+ val reportId = UUID.randomUUID()
+ val mockHistory = DetailedSubmissionHistory(
+ 1,
+ TaskAction.receive,
+ OffsetDateTime.now(),
+ reports = mutableListOf(),
+ logs = emptyList()
+ )
+ mockHistory.reportId = reportId.toString()
+ every { mockSubmissionsFacade.findDetailedSubmissionHistory(any(), any(), any()) } returns mockHistory
+
// act
val resp = reportFunc.processRequest(req, sender)
@@ -592,6 +614,8 @@ class ReportFunctionTests {
verify(exactly = 1) { engine.isDuplicateItem(any()) }
verify(exactly = 1) { actionHistory.trackActionSenderInfo(any(), any()) }
assert(resp.status.equals(HttpStatus.CREATED))
+ assertThat(resp.getHeader(HttpHeaders.LOCATION))
+ .isEqualTo("http://localhost/api/waters/report/$reportId/history")
}
// test processFunction when basic hl7 message with 5 separators is passed
diff --git a/prime-router/src/test/kotlin/history/SubmissionHistoryTests.kt b/prime-router/src/test/kotlin/history/SubmissionHistoryTests.kt
index d7d2a230753..151f48b9b88 100644
--- a/prime-router/src/test/kotlin/history/SubmissionHistoryTests.kt
+++ b/prime-router/src/test/kotlin/history/SubmissionHistoryTests.kt
@@ -1,8 +1,6 @@
package gov.cdc.prime.router.history
-import assertk.assertFailure
import assertk.assertThat
-import assertk.assertions.hasSize
import assertk.assertions.isEmpty
import assertk.assertions.isEqualTo
import assertk.assertions.isFalse
@@ -14,7 +12,6 @@ import com.microsoft.azure.functions.HttpStatus
import gov.cdc.prime.router.ActionLogLevel
import gov.cdc.prime.router.ActionLogScope
import gov.cdc.prime.router.ClientSource
-import gov.cdc.prime.router.ErrorCode
import gov.cdc.prime.router.FieldPrecisionMessage
import gov.cdc.prime.router.InvalidEquipmentMessage
import gov.cdc.prime.router.InvalidReportMessage
@@ -24,7 +21,6 @@ import gov.cdc.prime.router.ReportStreamFilterResult
import gov.cdc.prime.router.ReportStreamFilterType
import gov.cdc.prime.router.Topic
import gov.cdc.prime.router.azure.db.enums.TaskAction
-import gov.cdc.prime.router.fhirengine.engine.FHIRConverter
import java.time.OffsetDateTime
import java.util.UUID
import kotlin.test.Test
@@ -35,7 +31,7 @@ class SubmissionHistoryTests {
fun createLogs(logs: List): DetailedSubmissionHistory {
return DetailedSubmissionHistory(
1, TaskAction.receive, OffsetDateTime.now(),
- null, null, logs
+ null, mutableListOf(), logs
)
}
@@ -369,6 +365,8 @@ class SubmissionHistoryTests {
1,
TaskAction.receive,
OffsetDateTime.now(),
+ reports = mutableListOf(),
+ logs = emptyList()
).run {
assertThat(actionId).isEqualTo(1)
assertThat(createdAt).isNotNull()
@@ -380,7 +378,7 @@ class SubmissionHistoryTests {
assertThat(externalName).isEqualTo("")
assertThat(destinations.size).isEqualTo(0)
assertThat(destinationCount).isEqualTo(0)
- assertThat(reports?.size).isEqualTo(0)
+ assertThat(reports.size).isEqualTo(0)
assertThat(logs.size).isEqualTo(0)
}
DetailedSubmissionHistory(
@@ -388,7 +386,7 @@ class SubmissionHistoryTests {
TaskAction.receive,
OffsetDateTime.now(),
201,
- null,
+ mutableListOf(),
emptyList(),
).run {
assertThat(actionId).isEqualTo(1)
@@ -401,7 +399,7 @@ class SubmissionHistoryTests {
assertThat(externalName).isEqualTo("")
assertThat(destinations.size).isEqualTo(0)
assertThat(destinationCount).isEqualTo(0)
- assertThat(reports).isNull()
+ assertThat(reports).isEmpty()
assertThat(logs.size).isEqualTo(0)
}
@@ -410,7 +408,7 @@ class SubmissionHistoryTests {
TaskAction.receive,
OffsetDateTime.now(),
null,
- null,
+ mutableListOf(),
emptyList(),
).run {
assertThat(actionId).isEqualTo(1)
@@ -438,7 +436,10 @@ class SubmissionHistoryTests {
null,
5,
7,
- false
+ false,
+ null,
+ null,
+ null
)
val refUUID = UUID.randomUUID()
@@ -456,7 +457,10 @@ class SubmissionHistoryTests {
null,
1,
1,
- true
+ true,
+ null,
+ null,
+ null
),
DetailedReport(
UUID.randomUUID(),
@@ -470,7 +474,10 @@ class SubmissionHistoryTests {
null,
2,
null,
- true
+ true,
+ null,
+ null,
+ null
),
DetailedReport(
UUID.randomUUID(),
@@ -483,7 +490,10 @@ class SubmissionHistoryTests {
null,
0,
null,
- true
+ true,
+ null,
+ null,
+ null
),
).toMutableList()
@@ -549,19 +559,6 @@ class SubmissionHistoryTests {
assertThat(logs).isNotNull()
}
-
- reports = listOf(inputReport, inputReport).toMutableList()
-
- assertFailure {
- DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- null,
- reports,
- emptyList()
- )
- }
}
// Status calculation tests
@@ -575,6 +572,8 @@ class SubmissionHistoryTests {
TaskAction.receive,
OffsetDateTime.now(),
HttpStatus.BAD_REQUEST.value(),
+ reports = mutableListOf(),
+ logs = emptyList()
)
testError.enrichWithSummary()
testError.run {
@@ -592,6 +591,8 @@ class SubmissionHistoryTests {
TaskAction.receive,
OffsetDateTime.now(),
HttpStatus.OK.value(),
+ reports = mutableListOf(),
+ logs = emptyList()
)
testReceived.actionsPerformed = mutableSetOf(TaskAction.receive)
testReceived.enrichWithSummary()
@@ -602,7 +603,7 @@ class SubmissionHistoryTests {
val noDestinationsCalculatedYet = emptyList().toMutableList()
val testReceivedButNoDestinationsYet = DetailedSubmissionHistory(
1, TaskAction.route, OffsetDateTime.now(),
- HttpStatus.OK.value(), noDestinationsCalculatedYet
+ HttpStatus.OK.value(), noDestinationsCalculatedYet, logs = emptyList()
)
testReceivedButNoDestinationsYet.enrichWithSummary()
testReceivedButNoDestinationsYet.run {
@@ -621,7 +622,10 @@ class SubmissionHistoryTests {
null,
5,
null,
- false
+ false,
+ null,
+ null,
+ null
)
// received: one of two destinations has been calculated, with all items for it filtered out
val oneFilteredDestinationCalculated = listOf(
@@ -638,12 +642,15 @@ class SubmissionHistoryTests {
OffsetDateTime.now().plusDays(1),
0,
5,
- true
+ true,
+ null,
+ null,
+ null
),
).toMutableList()
val testReceivedOneFilteredDestination = DetailedSubmissionHistory(
1, TaskAction.route, OffsetDateTime.now(),
- HttpStatus.OK.value(), oneFilteredDestinationCalculated
+ HttpStatus.OK.value(), oneFilteredDestinationCalculated, logs = emptyList()
)
testReceivedOneFilteredDestination.enrichWithSummary()
testReceivedOneFilteredDestination.run {
@@ -664,7 +671,10 @@ class SubmissionHistoryTests {
null,
0,
null,
- true
+ true,
+ null,
+ null,
+ null
),
).toMutableList()
val testReceivedNoDestination = DetailedSubmissionHistory(
@@ -673,6 +683,7 @@ class SubmissionHistoryTests {
OffsetDateTime.now(),
HttpStatus.OK.value(),
reports,
+ emptyList()
)
testReceivedNoDestination.enrichWithSummary()
testReceivedNoDestination.run {
@@ -688,7 +699,8 @@ class SubmissionHistoryTests {
TaskAction.receive,
OffsetDateTime.now(),
HttpStatus.OK.value(),
- null,
+ reports = mutableListOf(),
+ logs = emptyList()
)
testReceived.actionsPerformed = mutableSetOf(TaskAction.receive)
testReceived.enrichWithSummary()
@@ -711,7 +723,10 @@ class SubmissionHistoryTests {
null,
0,
null,
- true
+ true,
+ null,
+ null,
+ null
),
).toMutableList()
val testReceivedNoDestination = DetailedSubmissionHistory(
@@ -720,6 +735,7 @@ class SubmissionHistoryTests {
OffsetDateTime.now(),
HttpStatus.OK.value(),
reports,
+ logs = emptyList()
)
testReceivedNoDestination.enrichWithSummary()
testReceivedNoDestination.run {
@@ -744,7 +760,10 @@ class SubmissionHistoryTests {
null,
5,
null,
- false
+ false,
+ null,
+ null,
+ null
)
val latestReport = DetailedReport(
UUID.randomUUID(),
@@ -757,7 +776,10 @@ class SubmissionHistoryTests {
null,
4,
null,
- true
+ true,
+ null,
+ null,
+ null
)
// waiting to deliver: one of two destinations has been calculated, with no items filtered out
val oneUnfilteredDestinationCalculated = listOf(
@@ -774,12 +796,15 @@ class SubmissionHistoryTests {
null,
5,
5,
- true
+ true,
+ null,
+ null,
+ null
),
).toMutableList()
val testReceivedOneUnfilteredDestination = DetailedSubmissionHistory(
1, TaskAction.route, OffsetDateTime.now(),
- HttpStatus.OK.value(), oneUnfilteredDestinationCalculated
+ HttpStatus.OK.value(), oneUnfilteredDestinationCalculated, logs = emptyList()
)
testReceivedOneUnfilteredDestination.enrichWithSummary()
testReceivedOneUnfilteredDestination.run {
@@ -801,7 +826,10 @@ class SubmissionHistoryTests {
null,
1,
null,
- true
+ true,
+ null,
+ null,
+ null
),
DetailedReport(
UUID.randomUUID(),
@@ -815,972 +843,19 @@ class SubmissionHistoryTests {
null,
0,
null,
- true
+ true,
+ null,
+ null,
+ null
),
).toMutableList()
val testWaitingToDeliver = DetailedSubmissionHistory(
1, TaskAction.receive, OffsetDateTime.now(),
- HttpStatus.OK.value(), reports
+ HttpStatus.OK.value(), reports, logs = emptyList()
)
testWaitingToDeliver.enrichWithSummary()
testWaitingToDeliver.run {
assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.WAITING_TO_DELIVER)
}
}
-
- @Test
- fun `test DetailedSubmissionHistory overallStatus (partially delivered)`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- null,
- false
- )
- // use cases found while investigating issue #9378
- // partially delivered: one destination with an item, the other got all filtered out
- val twoDestinationsOneItem = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg4",
- "recvSvc4",
- null,
- null,
- Topic.FULL_ELR,
- "one item dest",
- null,
- null,
- 1,
- 3,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg3",
- "recvSvc3",
- null,
- null,
- Topic.FULL_ELR,
- "all items filtered out",
- null,
- null,
- 0,
- 3,
- true
- ),
- ).toMutableList()
- val testPartiallyDeliveredTwoDestinations = DetailedSubmissionHistory(
- 1, TaskAction.route, OffsetDateTime.now(),
- HttpStatus.OK.value(), twoDestinationsOneItem
- )
- testPartiallyDeliveredTwoDestinations.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 1, TaskAction.send, OffsetDateTime.now(),
- HttpStatus.OK.value(), twoDestinationsOneItem
- ),
- )
- )
- testPartiallyDeliveredTwoDestinations.enrichWithSummary()
- testPartiallyDeliveredTwoDestinations.run {
- assertThat(destinations.count()).isEqualTo(2)
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.PARTIALLY_DELIVERED)
- }
- }
-
- @Test
- fun `test DetailedSubmissionHistory overallStatus (delivered)`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- null,
- false
- )
- // delivered: one destination with an item, the other got SOME items filtered out
- val twoDestinationsSomeItems = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg4",
- "recvSvc4",
- null,
- null,
- Topic.FULL_ELR,
- "one item dest",
- null,
- null,
- 1,
- 1,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg3",
- "recvSvc3",
- null,
- null,
- Topic.FULL_ELR,
- "all items filtered out",
- null,
- null,
- 1,
- 4,
- true
- ),
- ).toMutableList()
- val testDeliveredTwoDestinationsSomeItems = DetailedSubmissionHistory(
- 1, TaskAction.route, OffsetDateTime.now(),
- HttpStatus.OK.value(), twoDestinationsSomeItems
- )
- testDeliveredTwoDestinationsSomeItems.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 1, TaskAction.send, OffsetDateTime.now(),
- HttpStatus.OK.value(), twoDestinationsSomeItems
- ),
- )
- )
- testDeliveredTwoDestinationsSomeItems.enrichWithSummary()
- testDeliveredTwoDestinationsSomeItems.run {
- assertThat(destinations.count()).isEqualTo(2)
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.DELIVERED)
- }
- // delivered: all destinations received all items
- val everyDestinationGetsAllItems = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg4",
- "recvSvc4",
- null,
- null,
- Topic.FULL_ELR,
- "one item dest",
- null,
- null,
- 4,
- 4,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg3",
- "recvSvc3",
- null,
- null,
- Topic.FULL_ELR,
- "all items filtered out",
- null,
- null,
- 3,
- 3,
- true
- ),
- ).toMutableList()
- val testDeliveredToAllDestinations = DetailedSubmissionHistory(
- 1, TaskAction.route, OffsetDateTime.now(),
- HttpStatus.OK.value(), everyDestinationGetsAllItems
- )
- testDeliveredToAllDestinations.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 1, TaskAction.send, OffsetDateTime.now(),
- HttpStatus.OK.value(), everyDestinationGetsAllItems
- ),
- DetailedSubmissionHistory(
- 2, TaskAction.send, OffsetDateTime.now(),
- HttpStatus.OK.value(), everyDestinationGetsAllItems
- ),
- )
- )
- testDeliveredToAllDestinations.enrichWithSummary()
- testDeliveredToAllDestinations.run {
- assertThat(destinations.count()).isEqualTo(2)
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.DELIVERED)
- }
- }
-
- @Test
- fun `test DetailedSubmissionHistory UP overallStatus (not delivering)`() {
- // not delivering: one destination, all items filtered out
- val reportsAllItemsFilteredOut = listOf(
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg3",
- "recvSvc3",
- null,
- null,
- Topic.FULL_ELR,
- "no item count dest",
- null,
- null,
- 0,
- 5,
- true
- ),
- ).toMutableList()
- val testNotDelivering = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reportsAllItemsFilteredOut,
- )
- testNotDelivering.enrichWithSummary()
- testNotDelivering.run {
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.NOT_DELIVERING)
- }
- val reports = listOf(
- DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- null,
- null,
- Topic.FULL_ELR,
- "no item count dest",
- null,
- null,
- 0,
- null,
- true
- ),
- ).toMutableList()
- val testNotDeliveringNoDestination = DetailedSubmissionHistory(
- 1,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports,
- )
- testNotDeliveringNoDestination.actionsPerformed = mutableSetOf(TaskAction.route)
- testNotDeliveringNoDestination.enrichWithSummary()
- testNotDeliveringNoDestination.run {
- assertThat(destinationCount).isEqualTo(0)
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.NOT_DELIVERING)
- }
- }
-
- @Test
- fun `test DetailedSubmissionHistory LEGACY overallStatus calculations (not delivering)`() {
- var reports = listOf(
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg3",
- "recvSvc3",
- null,
- null,
- Topic.TEST,
- "no item count dest",
- null,
- null,
- 0,
- null,
- true
- ),
- ).toMutableList()
-
- val testNotDelivering = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports,
- )
- testNotDelivering.enrichWithSummary()
- testNotDelivering.run {
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.NOT_DELIVERING)
- assertThat(plannedCompletionAt).isNull()
- assertThat(actualCompletionAt).isNull()
- }
-
- reports = listOf(
- DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- null,
- null,
- Topic.TEST,
- "no item count dest",
- null,
- null,
- 0,
- null,
- true
- ),
- ).toMutableList()
- val testNotDeliveringNoDestination = DetailedSubmissionHistory(
- 1,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports,
- )
- testNotDeliveringNoDestination.actionsPerformed = mutableSetOf(TaskAction.route)
- testNotDeliveringNoDestination.enrichWithSummary()
- testNotDeliveringNoDestination.run {
- assertThat(destinationCount).isEqualTo(0)
- assertThat(overallStatus).isEqualTo(DetailedSubmissionHistory.Status.NOT_DELIVERING)
- assertThat(plannedCompletionAt).isNull()
- assertThat(actualCompletionAt).isNull()
- }
- }
-
- @Test
- fun `test Destination nextActionTime`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.TEST,
- "externalName",
- null,
- OffsetDateTime.now(),
- 3,
- null,
- false
- )
- val refUUID = UUID.randomUUID()
- val now = OffsetDateTime.now()
- val reports = listOf(
- inputReport,
- DetailedReport(
- refUUID, "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.TEST,
- "otherExternalName1",
- null,
- now,
- 1,
- 1,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg3",
- "recvSvc3",
- null,
- null, Topic.TEST,
- "no item count dest",
- null,
- now,
- 0,
- null,
- false
- ),
- ).toMutableList()
-
- DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- 201,
- reports,
- emptyList(),
- ).run {
- // First destination has a transport set therefore sendingAt
- assertThat(destinations.first().sendingAt).isEqualTo(now)
- assertThat(destinations.last().sendingAt).isNull()
- }
- }
-
- @Test
- fun `test Status enum toString`() {
- assertThat(DetailedSubmissionHistory.Status.RECEIVED.toString()).isEqualTo("Received")
- }
-
- @Test
- fun `test UP enrichWithDescendants stopped at route`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- 7,
- false
- )
-
- val refUUID = UUID.randomUUID()
-
- val reports = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- ),
- ).toMutableList()
-
- val logs = listOf(
- DetailedActionLog(
- ActionLogScope.translation,
- refUUID,
- null,
- "802798",
- ActionLogLevel.filter,
- ReportStreamFilterResult(
- "recvOrg1.recvSvc1",
- 1,
- "matches",
- listOf(
- "ordering_facility_county",
- "QUALITY_PASS"
- ),
- "802798",
- ReportStreamFilterType.QUALITY_FILTER
- )
- ),
- )
-
- val testEnrich = DetailedSubmissionHistory(
- 2,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports
- )
- assertThat(testEnrich.destinations.count()).isEqualTo(0)
- testEnrich.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 1,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- null,
- logs
- ),
- )
- )
-
- testEnrich.run {
- assertThat(destinations.count()).isEqualTo(1)
- assertThat(destinations.first().organizationId).isEqualTo("recvOrg1")
- assertThat(destinations.first().service).isEqualTo("recvSvc1")
- }
- }
-
- @Test
- fun `test UP enrichWithDescendants add details from the convert step`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- 7,
- false
- )
-
- val reports = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- ),
- ).toMutableList()
-
- val testEnrich = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports
- )
- val logs = listOf(
- DetailedActionLog(
- ActionLogScope.item,
- UUID.randomUUID(),
- 1,
- null,
- ActionLogLevel.error,
-
- FHIRConverter.InvalidItemActionLogDetail(
- ErrorCode.INVALID_MSG_VALIDATION,
- 0,
- "HL7 was not valid at OBX[1]-19[1].1"
- )
- ),
- )
- assertThat(testEnrich.destinations.count()).isEqualTo(0)
- testEnrich.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 2,
- TaskAction.convert,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- null,
- logs
- )
- )
- )
-
- testEnrich.run {
- assertThat(destinations.count()).isEqualTo(0)
- assertThat(errors).hasSize(1)
- }
- }
-
- @Test
- fun `test UP enrichWithDescendants reached translate`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- 7,
- false
- )
-
- val reports = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- ),
- ).toMutableList()
-
- val testEnrich = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports
- )
- assertThat(testEnrich.destinations.count()).isEqualTo(0)
- testEnrich.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 2,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- ),
- DetailedSubmissionHistory(
- 3,
- TaskAction.translate,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- mutableListOf(
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- )
- )
- ),
- )
- )
-
- testEnrich.run {
- assertThat(destinations.count()).isEqualTo(1)
- assertThat(destinations.first().organizationId).isEqualTo("recvOrg1")
- assertThat(destinations.first().service).isEqualTo("recvSvc1")
- }
- }
-
- @Test
- fun `test UP enrichWithDescendants reached translate multiple report same receiver`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- 7,
- false
- )
-
- val reports = listOf(
- inputReport,
- DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- ),
- ).toMutableList()
-
- val testEnrich = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- reports
- )
- assertThat(testEnrich.destinations.count()).isEqualTo(0)
- testEnrich.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 2,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- ),
- DetailedSubmissionHistory(
- 3,
- TaskAction.translate,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- mutableListOf(
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- null,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- null,
- true
- )
- )
- ),
- )
- )
-
- testEnrich.run {
- assertThat(destinations.count()).isEqualTo(1)
- assertThat(destinations.first().organizationId).isEqualTo("recvOrg1")
- assertThat(destinations.first().service).isEqualTo("recvSvc1")
- assertThat(destinations.first().itemCount).isEqualTo(3)
- assertThat(destinations.first().itemCountBeforeQualFilter).isEqualTo(1)
- }
- }
-
- @Test
- fun `test UP enrichWithDescendants reached translate multiple reports different receivers`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- 7,
- false
- )
-
- val testEnrich = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- mutableListOf(inputReport)
- )
- assertThat(testEnrich.destinations.count()).isEqualTo(0)
- testEnrich.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 2,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- ),
- DetailedSubmissionHistory(
- 3,
- TaskAction.translate,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- mutableListOf(
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- ),
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg2",
- "recvSvc2",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- 1,
- true
- )
- )
- ),
- )
- )
-
- testEnrich.run {
- assertThat(destinations.count()).isEqualTo(2)
- assertThat(destinations.first().organizationId).isEqualTo("recvOrg1")
- assertThat(destinations.first().service).isEqualTo("recvSvc1")
- }
- }
-
- @Test
- fun `test UP enrichWithDescendants filterLogs populate for the corresponding receiver`() {
- val inputReport = DetailedReport(
- UUID.randomUUID(),
- null,
- null,
- "org",
- "client",
- Topic.FULL_ELR,
- "externalName",
- null,
- null,
- 5,
- null,
- false
- )
-
- val testEnrich = DetailedSubmissionHistory(
- 1,
- TaskAction.receive,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- mutableListOf(inputReport)
- )
-
- val logs = listOf(
- DetailedActionLog(
- ActionLogScope.item,
- UUID.randomUUID(),
- 1,
- null,
- ActionLogLevel.error,
- InvalidEquipmentMessage("")
- ),
- DetailedActionLog(
- ActionLogScope.translation,
- UUID.randomUUID(),
- 2,
- null,
- ActionLogLevel.filter,
- ReportStreamFilterResult(
- "recvOrg1.recvSvc1",
- 5,
- "matches",
- listOf(
- "ordering_facility_county",
- "QUALITY_PASS"
- ),
- "802798",
- ReportStreamFilterType.QUALITY_FILTER
- )
- ),
- DetailedActionLog(
- ActionLogScope.translation,
- UUID.randomUUID(),
- 2,
- null,
- ActionLogLevel.filter,
- ReportStreamFilterResult(
- "recvOrg2.recvSvc2",
- 5,
- "matches",
- listOf(
- "ordering_facility_county",
- "QUALITY_PASS"
- ),
- "802798",
- ReportStreamFilterType.QUALITY_FILTER
- )
- ),
- DetailedActionLog(
- ActionLogScope.translation,
- UUID.randomUUID(),
- 2,
- null,
- ActionLogLevel.filter,
- ReportStreamFilterResult(
- "recvOrg1.recvSvc1",
- 5,
- "matches",
- listOf(
- "ordering_facility_county",
- "QUALITY_PASS"
- ),
- "802798",
- ReportStreamFilterType.QUALITY_FILTER
- )
- ),
- )
-
- assertThat(testEnrich.destinations.count()).isEqualTo(0)
- testEnrich.enrichWithDescendants(
- listOf(
- DetailedSubmissionHistory(
- 2,
- TaskAction.route,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- null,
- logs
- ),
- DetailedSubmissionHistory(
- 3,
- TaskAction.translate,
- OffsetDateTime.now(),
- HttpStatus.OK.value(),
- mutableListOf(
- DetailedReport(
- UUID.randomUUID(),
- "recvOrg1",
- "recvSvc1",
- null,
- null,
- Topic.FULL_ELR,
- "otherExternalName1",
- null,
- null,
- 1,
- null,
- true
- ),
- )
- )
- )
- )
-
- testEnrich.run {
- assertThat(destinations.count()).isEqualTo(2)
- assertThat(destinations.first().organizationId).isEqualTo("recvOrg1")
- assertThat(destinations.first().filteredReportItems?.count()).isEqualTo(2)
- assertThat(destinations.first().service).isEqualTo("recvSvc1")
- assertThat(destinations[1].service).isEqualTo("recvSvc2")
- assertThat(destinations[1].filteredReportItems?.count()).isEqualTo(1)
- }
- }
}
\ No newline at end of file
diff --git a/prime-router/src/test/kotlin/history/azure/SubmissionFunctionIntegrationTests.kt b/prime-router/src/test/kotlin/history/azure/SubmissionFunctionIntegrationTests.kt
new file mode 100644
index 00000000000..c215ad78dda
--- /dev/null
+++ b/prime-router/src/test/kotlin/history/azure/SubmissionFunctionIntegrationTests.kt
@@ -0,0 +1,541 @@
+package gov.cdc.prime.router.history.azure
+
+import assertk.assertThat
+import assertk.assertions.isEqualTo
+import assertk.assertions.isNotNull
+import gov.cdc.prime.router.ActionLog
+import gov.cdc.prime.router.ActionLogLevel
+import gov.cdc.prime.router.FileSettings
+import gov.cdc.prime.router.InvalidParamMessage
+import gov.cdc.prime.router.MimeFormat
+import gov.cdc.prime.router.Receiver
+import gov.cdc.prime.router.Report
+import gov.cdc.prime.router.Sender
+import gov.cdc.prime.router.Topic
+import gov.cdc.prime.router.azure.DataAccessTransaction
+import gov.cdc.prime.router.azure.DatabaseAccess
+import gov.cdc.prime.router.azure.MockHttpRequestMessage
+import gov.cdc.prime.router.azure.WorkflowEngine
+import gov.cdc.prime.router.azure.db.enums.TaskAction
+import gov.cdc.prime.router.azure.db.tables.pojos.Action
+import gov.cdc.prime.router.azure.db.tables.pojos.ItemLineage
+import gov.cdc.prime.router.azure.db.tables.pojos.ReportFile
+import gov.cdc.prime.router.azure.db.tables.pojos.ReportLineage
+import gov.cdc.prime.router.common.JacksonMapperUtilities
+import gov.cdc.prime.router.common.UniversalPipelineTestUtils
+import gov.cdc.prime.router.db.ReportStreamTestDatabaseContainer
+import gov.cdc.prime.router.db.ReportStreamTestDatabaseSetupExtension
+import gov.cdc.prime.router.history.DetailedSubmissionHistory
+import gov.cdc.prime.router.tokens.AuthenticatedClaims
+import gov.cdc.prime.router.tokens.AuthenticationType
+import gov.cdc.prime.router.tokens.oktaSystemAdminGroup
+import gov.cdc.prime.router.unittest.UnitTestUtils
+import io.mockk.every
+import io.mockk.mockkObject
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.testcontainers.junit.jupiter.Testcontainers
+import java.time.OffsetDateTime
+import java.util.UUID
+
+@Testcontainers
+@ExtendWith(ReportStreamTestDatabaseSetupExtension::class)
+class SubmissionFunctionIntegrationTests {
+
+ class ReportNodeBuilder {
+ lateinit var theAction: TaskAction
+ var theReportBlobUrl: String = UUID.randomUUID().toString()
+ var theItemCount: Int = 1
+ val reportGraphNodes: MutableList = mutableListOf()
+ var receiver: Receiver? = null
+ var logs: MutableList = mutableListOf()
+ var theTransportResult: String? = null
+
+ fun receiver(receiver: Receiver) {
+ this.receiver = receiver
+ }
+
+ fun action(action: TaskAction) {
+ this.theAction = action
+ }
+
+ fun reportBlobUrl(reportBlobUrl: String) {
+ this.theReportBlobUrl = reportBlobUrl
+ }
+
+ fun itemCount(itemCount: Int) {
+ this.theItemCount = itemCount
+ }
+
+ fun reportGraphNode(initializer: ReportNodeBuilder.() -> Unit) {
+ this.reportGraphNodes.add(ReportNodeBuilder().apply(initializer))
+ }
+
+ fun log(actionLog: ActionLog) {
+ this.logs.add(actionLog)
+ }
+
+ fun transportResult(transportResult: String) {
+ this.theTransportResult = transportResult
+ }
+ }
+
+ class ReportGraphNode(val node: ReportFile) {
+ val children: MutableList = mutableListOf()
+ }
+
+ class ReportGraphBuilder {
+ private lateinit var theSubmission: ReportNodeBuilder
+ private lateinit var theTopic: Topic
+ private lateinit var theFormat: MimeFormat
+ private lateinit var theSender: Sender
+
+ fun topic(topic: Topic) {
+ this.theTopic = topic
+ }
+
+ fun format(format: MimeFormat) {
+ this.theFormat = format
+ }
+
+ fun sender(sender: Sender) {
+ this.theSender = sender
+ }
+
+ fun submission(initializer: ReportNodeBuilder.() -> Unit) {
+ this.theSubmission = ReportNodeBuilder().apply(initializer)
+ }
+
+ fun generate(dbAccess: DatabaseAccess): ReportGraphNode {
+ if (!::theTopic.isInitialized) {
+ throw IllegalStateException("Topic must be set")
+ }
+ if (!::theFormat.isInitialized) {
+ throw IllegalStateException("Format must be set")
+ }
+ if (!::theSubmission.isInitialized) {
+ throw IllegalStateException("Root must be set")
+ }
+ val graph = dbAccess.transactReturning { txn ->
+ val report = Report(
+ theFormat,
+ emptyList(),
+ theSubmission.theItemCount,
+ metadata = UnitTestUtils.simpleMetadata,
+ // TODO
+ nextAction = TaskAction.convert,
+ topic = theTopic
+ )
+
+ val action = Action().setActionName(theSubmission.theAction).setExternalName("")
+ action.setSendingOrg(theSender.organizationName)
+ action.setSendingOrgClient(theSender.name)
+ action.setHttpStatus(201)
+ val actionId = dbAccess.insertAction(txn, action)
+ action.actionId = actionId
+ val reportFile = ReportFile()
+ .setSchemaTopic(theTopic)
+ .setReportId(report.id)
+ .setActionId(actionId)
+ .setSchemaName("")
+ .setSendingOrg(theSender.organizationName)
+ .setSendingOrgClient(theSender.name)
+ .setBodyFormat(theFormat.toString())
+ .setItemCount(theSubmission.theItemCount)
+ .setExternalName("test-external-name")
+ .setBodyUrl(theSubmission.theReportBlobUrl)
+ .setNextAction(theSubmission.reportGraphNodes.firstOrNull()?.theAction)
+ dbAccess.insertReportFile(
+ reportFile, txn, action
+ )
+
+ val graph = ReportGraphNode(reportFile)
+
+ theSubmission.reportGraphNodes.foldIndexed(graph) { nodeIndex, acc, node ->
+ acc.children.add(descend(node, dbAccess, txn, report, graph, nodeIndex))
+ acc
+ }
+ graph
+ }
+ return graph
+ }
+
+ private fun descend(
+ node: ReportNodeBuilder,
+ dbAccess: DatabaseAccess,
+ txn: DataAccessTransaction,
+ report: Report,
+ graph: ReportGraphNode,
+ nodeIndex: Int,
+ ): ReportGraphNode {
+ val childReport = Report(
+ theFormat,
+ emptyList(),
+ node.theItemCount,
+ metadata = UnitTestUtils.simpleMetadata,
+ nextAction = TaskAction.convert,
+ topic = theTopic
+ )
+ val childAction = Action().setActionName(node.theAction).setExternalName("")
+
+ if (node.receiver != null) {
+ childAction.setReceivingOrg(node.receiver!!.organizationName)
+ childAction.setReceivingOrgSvc(node.receiver!!.name)
+ }
+ val childActionId = dbAccess.insertAction(txn, childAction)
+ childAction.actionId = childActionId
+ val childReportFile = ReportFile()
+ .setSchemaTopic(theTopic)
+ .setReportId(childReport.id)
+ .setActionId(childActionId)
+ .setSchemaName("")
+ .setBodyFormat(theFormat.toString())
+ .setItemCount(node.theItemCount)
+ .setExternalName("test-external-name")
+ .setBodyUrl(node.theReportBlobUrl)
+ .setTransportResult(node.theTransportResult)
+ .setNextAction(node.reportGraphNodes.firstOrNull()?.theAction)
+
+ if (node.receiver != null) {
+ childReportFile.setReceivingOrg(node.receiver!!.organizationName)
+ childReportFile.setReceivingOrgSvc(node.receiver!!.name)
+ }
+ dbAccess.insertReportFile(
+ childReportFile, txn, childAction
+ )
+ node.logs.forEach { log ->
+ log.action = childAction
+ log.reportId = childReport.id
+ dbAccess.insertActionLog(log, txn)
+ }
+
+ dbAccess.insertReportLineage(
+ ReportLineage(
+ null,
+ childActionId,
+ graph.node.reportId,
+ childReportFile.reportId,
+ OffsetDateTime.now()
+ ),
+ txn
+ )
+
+ dbAccess.insertItemLineages(
+ setOf(
+ ItemLineage(
+ null,
+ graph.node.reportId,
+ 1,
+ childReportFile.reportId,
+ nodeIndex + 1,
+ null,
+ null,
+ null,
+ ""
+ )
+ ),
+ txn, childAction
+ )
+ val childGraph = ReportGraphNode(childReportFile)
+ node.reportGraphNodes.foldIndexed(graph) { childNodeIndex, acc, descendant ->
+ descend(descendant, dbAccess, txn, report, childGraph, childNodeIndex)
+ acc
+ }
+ return childGraph
+ }
+ }
+
+ fun reportGraph(initializer: ReportGraphBuilder.() -> Unit): ReportGraphBuilder {
+ return ReportGraphBuilder().apply(initializer)
+ }
+
+ @Test
+ fun `it should return a history for partially delivered submission`() {
+ val submittedReport = reportGraph {
+ topic(Topic.FULL_ELR)
+ format(MimeFormat.HL7)
+ sender(UniversalPipelineTestUtils.hl7Sender)
+
+ submission {
+ action(TaskAction.receive)
+ reportGraphNode {
+ action(TaskAction.convert)
+ log(ActionLog(InvalidParamMessage("log"), type = ActionLogLevel.warning))
+ reportGraphNode {
+ action(TaskAction.route)
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ itemCount(0)
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.route)
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ itemCount(0)
+ }
+ }
+ }
+ }
+ }.generate(ReportStreamTestDatabaseContainer.testDatabaseAccess)
+
+ val httpRequestMessage = MockHttpRequestMessage()
+
+ val func = setupSubmissionFunction()
+
+ val history = func
+ .getReportDetailedHistory(httpRequestMessage, submittedReport.node.reportId.toString())
+ assertThat(history).isNotNull()
+ val historyNode = JacksonMapperUtilities.defaultMapper.readTree(history.body.toString())
+ assertThat(
+ historyNode.get("overallStatus").asText()
+ ).isEqualTo(DetailedSubmissionHistory.Status.PARTIALLY_DELIVERED.toString())
+ assertThat(historyNode.get("destinations").size()).isEqualTo(2)
+ assertThat(historyNode.get("errors").size()).isEqualTo(0)
+ assertThat(historyNode.get("warnings").size()).isEqualTo(1)
+ }
+
+ @Test
+ fun `it should return a history that a submission has been received`() {
+ val submittedReport = reportGraph {
+ topic(Topic.FULL_ELR)
+ format(MimeFormat.HL7)
+ sender(UniversalPipelineTestUtils.hl7Sender)
+
+ submission {
+ action(TaskAction.receive)
+ }
+ }.generate(ReportStreamTestDatabaseContainer.testDatabaseAccess)
+
+ val httpRequestMessage = MockHttpRequestMessage()
+
+ val func = setupSubmissionFunction()
+
+ val history = func
+ .getReportDetailedHistory(httpRequestMessage, submittedReport.node.reportId.toString())
+ assertThat(history).isNotNull()
+ val historyNode = JacksonMapperUtilities.defaultMapper.readTree(history.body.toString())
+ assertThat(
+ historyNode.get("overallStatus").asText()
+ ).isEqualTo(DetailedSubmissionHistory.Status.RECEIVED.toString())
+ assertThat(historyNode.get("destinations").size()).isEqualTo(0)
+ assertThat(historyNode.get("errors").size()).isEqualTo(0)
+ assertThat(historyNode.get("warnings").size()).isEqualTo(0)
+ }
+
+ @Test
+ fun `it should return a history that indicates the report is not going to be delivered`() {
+ val submittedReport = reportGraph {
+ topic(Topic.FULL_ELR)
+ format(MimeFormat.HL7)
+ sender(UniversalPipelineTestUtils.hl7Sender)
+
+ submission {
+ action(TaskAction.receive)
+ reportGraphNode {
+ action(TaskAction.convert)
+ log(ActionLog(InvalidParamMessage("log"), type = ActionLogLevel.warning))
+ reportGraphNode {
+ action(TaskAction.route)
+ }
+ }
+ }
+ }.generate(ReportStreamTestDatabaseContainer.testDatabaseAccess)
+
+ val httpRequestMessage = MockHttpRequestMessage()
+
+ val func = setupSubmissionFunction()
+
+ val history = func
+ .getReportDetailedHistory(httpRequestMessage, submittedReport.node.reportId.toString())
+ assertThat(history).isNotNull()
+ val historyNode = JacksonMapperUtilities.defaultMapper.readTree(history.body.toString())
+ assertThat(
+ historyNode.get("overallStatus").asText()
+ ).isEqualTo(DetailedSubmissionHistory.Status.NOT_DELIVERING.toString())
+ assertThat(historyNode.get("destinations").size()).isEqualTo(0)
+ assertThat(historyNode.get("errors").size()).isEqualTo(0)
+ assertThat(historyNode.get("warnings").size()).isEqualTo(1)
+ }
+
+ @Test
+ fun `it should return a history that indicates waiting to deliver`() {
+ val submittedReport = reportGraph {
+ topic(Topic.FULL_ELR)
+ format(MimeFormat.HL7)
+ sender(UniversalPipelineTestUtils.hl7Sender)
+
+ submission {
+ action(TaskAction.receive)
+ reportGraphNode {
+ action(TaskAction.convert)
+ log(ActionLog(InvalidParamMessage("log"), type = ActionLogLevel.warning))
+ reportGraphNode {
+ action(TaskAction.route)
+ log(ActionLog(InvalidParamMessage("log"), type = ActionLogLevel.error))
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.route)
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ }
+ }
+ }
+ }
+ }.generate(ReportStreamTestDatabaseContainer.testDatabaseAccess)
+
+ val httpRequestMessage = MockHttpRequestMessage()
+
+ val func = setupSubmissionFunction()
+
+ val history = func
+ .getReportDetailedHistory(httpRequestMessage, submittedReport.node.reportId.toString())
+ assertThat(history).isNotNull()
+ val historyNode = JacksonMapperUtilities.defaultMapper.readTree(history.body.toString())
+ assertThat(
+ historyNode.get("overallStatus").asText()
+ ).isEqualTo(DetailedSubmissionHistory.Status.WAITING_TO_DELIVER.toString())
+ assertThat(historyNode.get("destinations").size()).isEqualTo(2)
+ assertThat(historyNode.get("errors").size()).isEqualTo(1)
+ assertThat(historyNode.get("warnings").size()).isEqualTo(1)
+ }
+
+ @Test
+ fun `it should return history of a submission that is delivered`() {
+ val submittedReport = reportGraph {
+ topic(Topic.FULL_ELR)
+ format(MimeFormat.HL7)
+ sender(UniversalPipelineTestUtils.hl7Sender)
+
+ submission {
+ action(TaskAction.receive)
+ reportGraphNode {
+ action(TaskAction.convert)
+ log(ActionLog(InvalidParamMessage("log"), type = ActionLogLevel.warning))
+ reportGraphNode {
+ action(TaskAction.route)
+ log(ActionLog(InvalidParamMessage("log"), type = ActionLogLevel.error))
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ }
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.route)
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[0])
+ }
+ }
+ reportGraphNode {
+ action(TaskAction.translate)
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ reportGraphNode {
+ action(TaskAction.send)
+ transportResult("Success")
+ receiver(UniversalPipelineTestUtils.universalPipelineOrganization.receivers[1])
+ }
+ }
+ }
+ }
+ }
+ }.generate(ReportStreamTestDatabaseContainer.testDatabaseAccess)
+
+ val httpRequestMessage = MockHttpRequestMessage()
+
+ val func = setupSubmissionFunction()
+
+ val history = func
+ .getReportDetailedHistory(httpRequestMessage, submittedReport.node.reportId.toString())
+ assertThat(history).isNotNull()
+ val historyNode = JacksonMapperUtilities.defaultMapper.readTree(history.body.toString())
+ assertThat(
+ historyNode.get("overallStatus").asText()
+ ).isEqualTo(DetailedSubmissionHistory.Status.DELIVERED.toString())
+ assertThat(historyNode.get("destinations").size()).isEqualTo(2)
+ assertThat(historyNode.get("errors").size()).isEqualTo(1)
+ assertThat(historyNode.get("warnings").size()).isEqualTo(1)
+ assertThat(historyNode.get("sender").asText()).isEqualTo("phd.elr-hl7-sender")
+ assertThat(historyNode.get("actualCompletionAt").asText()).isNotNull()
+ }
+
+ @BeforeEach
+ fun setupAuth() {
+ val jwt = mapOf("organization" to listOf(oktaSystemAdminGroup), "sub" to "test@cdc.gov")
+ val claims = AuthenticatedClaims(jwt, AuthenticationType.Okta)
+ mockkObject(AuthenticatedClaims)
+ every { AuthenticatedClaims.authenticate(any()) } returns claims
+ }
+
+ private fun setupSubmissionFunction(): SubmissionFunction {
+ val workflowEngine = WorkflowEngine
+ .Builder()
+ .metadata(UnitTestUtils.simpleMetadata)
+ .settingsProvider(
+ FileSettings().loadOrganizations(UniversalPipelineTestUtils.universalPipelineOrganization)
+ )
+ .databaseAccess(ReportStreamTestDatabaseContainer.testDatabaseAccess)
+ .build()
+ return SubmissionFunction(
+ SubmissionsFacade(
+ DatabaseSubmissionsAccess(ReportStreamTestDatabaseContainer.testDatabaseAccess),
+ ReportStreamTestDatabaseContainer.testDatabaseAccess
+ ),
+ workflowEngine,
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/prime-router/src/test/kotlin/history/azure/SubmissionFunctionTests.kt b/prime-router/src/test/kotlin/history/azure/SubmissionFunctionTests.kt
index 239d3226be8..43317c09259 100644
--- a/prime-router/src/test/kotlin/history/azure/SubmissionFunctionTests.kt
+++ b/prime-router/src/test/kotlin/history/azure/SubmissionFunctionTests.kt
@@ -457,7 +457,7 @@ class SubmissionFunctionTests : Logging {
// Good return
val returnBody = DetailedSubmissionHistory(
550, TaskAction.receive, OffsetDateTime.now(), 201,
- null
+ mutableListOf(), emptyList()
)
// Happy path with a good UUID
val action = Action()
@@ -466,8 +466,9 @@ class SubmissionFunctionTests : Logging {
action.actionName = TaskAction.receive
every { mockSubmissionFacade.fetchActionForReportId(any()) } returns action
every { mockSubmissionFacade.fetchAction(any()) } returns null // not used for a UUID
- every { mockSubmissionFacade.findDetailedSubmissionHistory(any()) } returns returnBody
+ every { mockSubmissionFacade.findDetailedSubmissionHistory(any(), any(), any()) } returns returnBody
every { mockSubmissionFacade.checkAccessAuthorizationForAction(any(), any(), any()) } returns true
+ every { mockSubmissionFacade.fetchReportForActionId(any(), any()) } returns null
response = function.getReportDetailedHistory(mockRequest, goodUuid)
assertThat(response.status).isEqualTo(HttpStatus.OK)
var responseBody: DetailSubmissionHistoryResponse = mapper.readValue(response.body.toString())
@@ -498,7 +499,7 @@ class SubmissionFunctionTests : Logging {
// Happy path with a good actionId
every { mockSubmissionFacade.fetchActionForReportId(any()) } returns null // not used for an actionId
every { mockSubmissionFacade.fetchAction(any()) } returns action
- every { mockSubmissionFacade.findDetailedSubmissionHistory(any()) } returns returnBody
+ every { mockSubmissionFacade.findDetailedSubmissionHistory(any(), any(), any()) } returns returnBody
every { mockSubmissionFacade.checkAccessAuthorizationForAction(any(), any(), any()) } returns true
response = function.getReportDetailedHistory(mockRequest, goodActionId)
assertThat(response.status).isEqualTo(HttpStatus.OK)
@@ -678,7 +679,7 @@ class SubmissionFunctionTests : Logging {
every { anyConstructed().getDescendantReports(any(), any(), any()) } returns emptyList()
every { mockSubmissionFacade.fetchActionForReportId(any()) } returns action
every { mockSubmissionFacade.fetchAction(any()) } returns null // not used for a UUID
- every { mockSubmissionFacade.findDetailedSubmissionHistory(any()) } returns null
+ every { mockSubmissionFacade.findDetailedSubmissionHistory(any(), any(), any()) } returns null
every { mockSubmissionFacade.checkAccessAuthorizationForAction(any(), any(), any()) } returns true
val restCreds = mockk()
@@ -724,13 +725,15 @@ class SubmissionFunctionTests : Logging {
val detailedReport = DetailedReport(
UUID.randomUUID(),
"flexion", "flexion", "lab", "lab", Topic.ETOR_TI, "external",
- null, null, 1, 1, true
+ null, null, 1, 1, true, null,
+ null,
+ null
)
// Good return
val returnBody = DetailedSubmissionHistory(
550, TaskAction.receive, OffsetDateTime.now(), 201,
- mutableListOf(detailedReport)
+ mutableListOf(detailedReport), emptyList()
)
returnBody.destinations = listOf(
@@ -762,7 +765,7 @@ class SubmissionFunctionTests : Logging {
} returns listOf(firstReport, secondReport)
every { mockSubmissionFacade.fetchActionForReportId(any()) } returns action
every { mockSubmissionFacade.fetchAction(any()) } returns null // not used for a UUID
- every { mockSubmissionFacade.findDetailedSubmissionHistory(any()) } returns returnBody
+ every { mockSubmissionFacade.findDetailedSubmissionHistory(any(), any(), any()) } returns returnBody
every { mockSubmissionFacade.checkAccessAuthorizationForAction(any(), any(), any()) } returns true
val restCreds = mockk()
@@ -815,13 +818,15 @@ class SubmissionFunctionTests : Logging {
val detailedReport = DetailedReport(
UUID.randomUUID(),
"flexion", "flexion", "lab", "lab", Topic.ETOR_TI, "external",
- null, null, 1, 1, true
+ null, null, 1, 1, true, null,
+ null,
+ null
)
// Good return
val returnBody = DetailedSubmissionHistory(
550, TaskAction.receive, OffsetDateTime.now(), 201,
- mutableListOf(detailedReport)
+ mutableListOf(detailedReport), emptyList()
)
returnBody.destinations = listOf(
@@ -853,7 +858,7 @@ class SubmissionFunctionTests : Logging {
} returns listOf(firstReport, secondReport)
every { mockSubmissionFacade.fetchActionForReportId(any()) } returns action
every { mockSubmissionFacade.fetchAction(any()) } returns null // not used for a UUID
- every { mockSubmissionFacade.findDetailedSubmissionHistory(any()) } returns returnBody
+ every { mockSubmissionFacade.findDetailedSubmissionHistory(any(), any(), any()) } returns returnBody
every { mockSubmissionFacade.checkAccessAuthorizationForAction(any(), any(), any()) } returns true
val restCreds = mockk()
diff --git a/prime-router/src/test/kotlin/history/azure/SubmissionsFacadeTests.kt b/prime-router/src/test/kotlin/history/azure/SubmissionsFacadeTests.kt
index d9d13a55e9a..d2501faf4a0 100644
--- a/prime-router/src/test/kotlin/history/azure/SubmissionsFacadeTests.kt
+++ b/prime-router/src/test/kotlin/history/azure/SubmissionsFacadeTests.kt
@@ -3,21 +3,15 @@ package gov.cdc.prime.router.history.azure
import assertk.assertFailure
import assertk.assertThat
import assertk.assertions.hasMessage
-import assertk.assertions.isEqualTo
import assertk.assertions.isFalse
import assertk.assertions.isTrue
import com.google.common.net.HttpHeaders
import gov.cdc.prime.router.azure.DatabaseAccess
import gov.cdc.prime.router.azure.MockHttpRequestMessage
-import gov.cdc.prime.router.azure.db.enums.TaskAction
import gov.cdc.prime.router.azure.db.tables.pojos.Action
-import gov.cdc.prime.router.history.DetailedSubmissionHistory
import gov.cdc.prime.router.tokens.AuthenticatedClaims
import gov.cdc.prime.router.tokens.AuthenticationType
-import io.mockk.every
import io.mockk.mockk
-import java.time.OffsetDateTime
-import java.util.UUID
import kotlin.test.Test
class SubmissionsFacadeTests {
@@ -56,50 +50,6 @@ class SubmissionsFacadeTests {
}.hasMessage("Invalid organization.")
}
- @Test
- fun `test findDetailedSubmissionHistory`() {
- val mockSubmissionAccess = mockk()
- val mockDbAccess = mockk()
- val facade = SubmissionsFacade(mockSubmissionAccess, mockDbAccess)
- // Good return
- val goodReturn = DetailedSubmissionHistory(
- 550, TaskAction.receive, OffsetDateTime.now(),
- null, null, emptyList()
- )
- every {
- mockSubmissionAccess.fetchAction(
- any(),
- any(),
- DetailedSubmissionHistory::class.java
- )
- } returns goodReturn
-
- // No lineage since we have no report ID
- val action1 = Action()
- action1.actionId = 550
- action1.sendingOrg = "myOrg"
- action1.actionName = TaskAction.receive
- assertThat(facade.findDetailedSubmissionHistory(action1)).isEqualTo(goodReturn)
-
- // Happy path
- goodReturn.reportId = UUID.randomUUID().toString()
- every {
- mockSubmissionAccess.fetchRelatedActions(
- UUID.fromString(goodReturn.reportId), DetailedSubmissionHistory::class.java
- )
- } returns emptyList()
- assertThat(facade.findDetailedSubmissionHistory(action1)).isEqualTo(goodReturn)
- // Failures
- val action2 = Action()
- action2.actionId = 550
- action2.sendingOrg = "myOrg" // good
- action2.actionName = TaskAction.process // bad. Submission queries only work on receive actions.
- assertFailure { facade.findDetailedSubmissionHistory(action2) } // not a receive action
- action2.actionName = TaskAction.receive // good
- action2.sendingOrg = null // bad
- assertFailure { facade.findDetailedSubmissionHistory(action2) } // missing sendingOrg
- }
-
@Test
fun `test checkAccessAuthorizationForOrg`() {
val mockSubmissionAccess = mockk()