Skip to content

Commit

Permalink
Dev feature unit tests (#167)
Browse files Browse the repository at this point in the history
* Add fields jurisdiction, senderId to ReportDeadLetter

* Update sort

* Unit Test for getUploads

* Send Date with milliseconds for getUploads.
Sort the items in the Page after the page data is returned.

* Unit Tests for getUploads

* ReportCounts tests
  • Loading branch information
mtammineni authored Aug 21, 2024
1 parent 97c222f commit b791651
Show file tree
Hide file tree
Showing 13 changed files with 767 additions and 49 deletions.
11 changes: 11 additions & 0 deletions pstatus-graphql-ktor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"
testImplementation "io.ktor:ktor-server-tests-jvm:$ktor_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"

// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
// testImplementation 'org.mockito:mockito-core:4.6.1'
// testImplementation 'org.mockito:mockito-junit-jupiter:4.6.1'

testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.1"
testImplementation "org.junit.jupiter:junit-jupiter-engine:5.8.1"
testImplementation "org.mockito:mockito-core:4.5.1"
testImplementation "org.mockito:mockito-inline:4.5.1"
testImplementation "io.mockk:mockk:1.13.9"
testImplementation 'io.insert-koin:koin-test:3.4.3'
}

ktor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ open class CosmosLoader: KoinComponent {

private val cosmosRepository by inject<CosmosRepository>()

protected val reportsContainer = cosmosRepository.reportsContainer
protected var reportsContainer = cosmosRepository.reportsContainer

protected val logger = KotlinLogging.logger {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import gov.cdc.ocio.processingstatusapi.models.dao.ReportDao
import gov.cdc.ocio.processingstatusapi.models.query.UploadCounts
import gov.cdc.ocio.processingstatusapi.utils.DateUtils
import gov.cdc.ocio.processingstatusapi.utils.PageUtils
import gov.cdc.ocio.processingstatusapi.utils.SortUtils

class UploadStatusLoader: CosmosLoader() {

Expand Down Expand Up @@ -38,8 +39,7 @@ class UploadStatusLoader: CosmosLoader() {
pageNumber: Int,
sortBy: String?,
sortOrder: String?,
fileName:String?,
status: String?
fileName:String?
): UploadsStatus {

logger.info("dataStreamId = $dataStreamId")
Expand All @@ -63,10 +63,6 @@ class UploadStatusLoader: CosmosLoader() {
sqlQuery.append(" and r.content.filename = '$fileName'")
}

status?.run {
sqlQuery.append(" and r.stageInfo.status = '$status'")
}

dateStart?.run {
val dateStartEpochSecs = DateUtils.getEpochFromDateString(dateStart, "date_start")
sqlQuery.append(" and r.dexIngestDateTime >= $dateStartEpochSecs")
Expand All @@ -76,39 +72,48 @@ class UploadStatusLoader: CosmosLoader() {
sqlQuery.append(" and r.dexIngestDateTime < $dateEndEpochSecs")
}

sqlQuery.append(" group by r.uploadId")
sqlQuery.append(" group by r.uploadId, r.jurisdiction, r.senderId")

// Check the sort field as well to add them to the group by clause
var sortByQueryStr = StringBuilder()
sortBy.run {
val sortField = when (sortBy) {
"date" -> "dexIngestDateTime" // "group by _ts" is already added by default above
"fileName" -> "content.filename"
"dataStreamId" -> "dataStreamId"
"dataStreamRoute" -> "dataStreamRoute"
"service" -> "stageInfo.service"
"action" -> "stageInfo.action"
"jurisdiction" -> "jurisdiction"
"status" -> "stageInfo.status"
else -> {
return@run
}
}
//Add the sort by fields to grouping
sqlQuery.append(" , r.$sortField, r.jurisdiction, r.senderId")

var sortOrderVal = DEFAULT_SORT_ORDER
sortOrder?.run {
sortOrderVal = when (sortOrder) {
"ascending" -> "asc"
"descending" -> "desc"
else -> {
return@run
if (sortBy != null) {
if (sortBy.isNotEmpty()) {
val sortField = when (sortBy) {
"date" -> "dexIngestDateTime" // "group by _ts" is already added by default above
"fileName" -> "content.filename"
"dataStreamId" -> "dataStreamId"
"dataStreamRoute" -> "dataStreamRoute"
"service" -> "stageInfo.service"
"action" -> "stageInfo.action"
"jurisdiction" -> "jurisdiction"
"status" -> "stageInfo.status"
else -> {
throw BadRequestException("Invalid sort field: $sortBy")
}
}
//Add the sort by fields to grouping
sqlQuery.append(" , r.$sortField")

var sortOrderVal = DEFAULT_SORT_ORDER

sortOrder?.run {
if (sortOrder.isNotEmpty()) {
sortOrderVal = when (sortOrder.lowercase()) {
"asc", "ascending" -> "asc"
"desc", "descending" -> "desc"
else -> {
throw BadRequestException("Invalid sort order: $sortOrder")
}
}
}

}
//Sort By/ Order By the given sort field
sortByQueryStr.append(" order by r.$sortField $sortOrderVal")
}
}
//Sort By/ Order By the given sort field
sortByQueryStr.append(" order by r.$sortField $sortOrderVal")


}

Expand Down Expand Up @@ -186,8 +191,14 @@ class UploadStatusLoader: CosmosLoader() {
uploadsStatus.summary.pageSize = pageSize
uploadsStatus.summary.numberOfPages = numberOfPages
uploadsStatus.summary.totalItems = totalItems
uploadsStatus.summary.senderIds = senderIds
uploadsStatus.summary.jurisdictions = jurisdictions
uploadsStatus.summary.senderIds = senderIds.toMutableList()
uploadsStatus.summary.jurisdictions = jurisdictions.toMutableList()

if(sortOrder.isNullOrEmpty()){
SortUtils.sortByField(uploadsStatus, sortBy.toString(), DEFAULT_SORT_ORDER)
}else{
SortUtils.sortByField(uploadsStatus, sortBy.toString(), sortOrder.toString())
}

return uploadsStatus
}
Expand All @@ -197,6 +208,6 @@ class UploadStatusLoader: CosmosLoader() {
private const val MAX_PAGE_SIZE = 10000
const val DEFAULT_PAGE_SIZE = 100

private const val DEFAULT_SORT_ORDER = "asc"
private const val DEFAULT_SORT_ORDER = "desc"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ data class ReportDeadLetter(
var deadLetterReasons: List<String>? = null,

@GraphQLDescription("Schemas used to validate the report")
var validationSchemas: List<String>? = null
var validationSchemas: List<String>? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ data class ReportDeadLetterDao(
this.dispositionType = this@ReportDeadLetterDao.dispositionType
this.deadLetterReasons = this@ReportDeadLetterDao.deadLetterReasons
this.validationSchemas = this@ReportDeadLetterDao.validationSchemas
this.jurisdiction = this@ReportDeadLetterDao.jurisdiction
this.senderId = this@ReportDeadLetterDao.senderId
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ data class PageSummary(
var totalItems: Int = 0,

@GraphQLDescription("List of all the senderIds in the entire dataset matching the search criteria, not just this page.")
var senderIds: List<String> = listOf(),
var senderIds: MutableList<String> = mutableListOf(),

@GraphQLDescription("List of all the jurisdictions in the entire dataset matching the search criteria, not just this page.")
var jurisdictions: List<String> = listOf()
var jurisdictions: MutableList<String> = mutableListOf()
)
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,12 @@ class UploadQueryService : Query {
+ "`desc`: Descending order\n"
+ "If a value is provided that is not supported then a bad request response is returned."
)
sortOrder: String?,
sortOrder: String? = null,

@GraphQLDescription(
"*File Name* Search by the provided File Name:\n"
)
fileName: String? = null,

@GraphQLDescription(
"*Status* Search by the status of the upload:\n"
)
status: String? = null) =
fileName: String? = null) =
UploadStatusLoader().getUploadStatus(dataStreamId,
dataStreamRoute,
dateStart,
Expand All @@ -77,8 +72,7 @@ class UploadQueryService : Query {
pageNumber,
sortBy,
sortOrder,
fileName,
status)
fileName)

@GraphQLDescription("Return various uploads statistics")
@Suppress("unused")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object DateUtils {
var dateFormat = FastDateFormat.getInstance(DATE_FORMAT)
// Parse the date string to a Date object
val date = dateFormat.parse(dateStr)
return date.time / 1000 // convert to secs from millisecs
return date.time // time with millisecs
} catch (e: ParseException) {
throw BadRequestException("Failed to parse $fieldName: $dateStr. Format should be: ${DATE_FORMAT}.")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package gov.cdc.ocio.processingstatusapi.utils

import gov.cdc.ocio.processingstatusapi.models.query.UploadsStatus

/**
* Utility class for sorting operations on UploadsStatus.
*/
object SortUtils {

private enum class SortOrder { ASC, DESC }

/**
* Sorts the items in UploadsStatus based on the specified field and order.
*
* @param uploadsStatus The UploadsStatus instance to be sorted.
* @param field The field name to sort by.
* @param order The order to sort in ("asc" or "desc").
*/
fun sortByField(uploadsStatus: UploadsStatus, field: String, order: String) {
val sortOrder = try {
SortOrder.valueOf(order.uppercase())
} catch (e: IllegalArgumentException) {
throw IllegalArgumentException("Unsupported order: $order")
}

when (field) {
"date" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy { it.timestamp }
} else {
uploadsStatus.items.sortByDescending { it.timestamp }
}
}
"fileName" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy { it.fileName }
} else {
uploadsStatus.items.sortByDescending { it.fileName }
}
}
"dataStreamId" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy {
(it.metadata?.get("data_stream_id") as? String)?.toLowerCase() ?: ""
}
} else {
uploadsStatus.items.sortByDescending {
(it.metadata?.get("data_stream_id") as? String)?.toLowerCase() ?: ""
}
}
}
"dataStreamRoute" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy {
(it.metadata?.get("data_stream_route") as? String)?.toLowerCase() ?: ""
}
} else {
uploadsStatus.items.sortByDescending {
(it.metadata?.get("data_stream_route") as? String)?.toLowerCase() ?: ""
}
}
}
"status" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy { it.status }
} else {
uploadsStatus.items.sortByDescending { it.status }
}
}
"jurisdiction" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy { it.jurisdiction }
} else {
uploadsStatus.items.sortByDescending { it.jurisdiction }
}
}
"senderId" -> {
if (sortOrder == SortOrder.ASC) {
uploadsStatus.items.sortBy { it.senderId }
} else {
uploadsStatus.items.sortByDescending { it.senderId }
}
}
else -> uploadsStatus.items.sortByDescending { it.timestamp }
}


//Sort the senderIds and jurisdiction fields in the PageSummary
uploadsStatus.summary.senderIds.sort()
uploadsStatus.summary.jurisdictions.sort()

}
}
Loading

0 comments on commit b791651

Please sign in to comment.