diff --git a/adapter/adapter-service/src/main/scala/net/shrine/adapter/components/HeldQueries.scala b/adapter/adapter-service/src/main/scala/net/shrine/adapter/components/HeldQueries.scala
index 606bf713a..a2d58af4d 100644
--- a/adapter/adapter-service/src/main/scala/net/shrine/adapter/components/HeldQueries.scala
+++ b/adapter/adapter-service/src/main/scala/net/shrine/adapter/components/HeldQueries.scala
@@ -1,59 +1,60 @@
package net.shrine.adapter.components
import net.shrine.protocol.RunHeldQueryRequest
import net.shrine.protocol.ShrineResponse
import net.shrine.protocol.BroadcastMessage
import net.shrine.adapter.dao.model.ShrineQueryResult
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.ResultOutputType
import net.shrine.protocol.ErrorResponse
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.RunQueryResponse
import net.shrine.adapter.dao.AdapterDao
import net.shrine.adapter.RunQueryAdapter
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
/**
* @author clint
* @date May 2, 2014
*/
final case class HeldQueries(dao: AdapterDao, runQueryAdapter: RunQueryAdapter) {
def run(req: RunHeldQueryRequest): ShrineResponse = {
val queryId = req.networkQueryId
//TODO: Revisit this, we might want to store/retrieve the output types used originally.
val outputTypes: Set[ResultOutputType] = Set(ResultOutputType.PATIENT_COUNT_XML)
dao.findQueryByNetworkId(queryId) match {
case Some(savedQuery) => {
//Re-un the query with the original credentials, not an admin's
val savedAuthn = AuthenticationInfo(savedQuery.domain, savedQuery.username, Credential("", false))
val runQueryReq = RunQueryRequest(
req.projectId,
req.waitTime,
savedAuthn,
queryId,
- None, //topic id
+ topicId = None,
+ topicName = None,
outputTypes,
savedQuery.queryDefinition)
val newBroadcastMessage = BroadcastMessage(savedAuthn, runQueryReq)
dao.inTransaction {
//Delete previous records for this query from the DB, so we don't have obsolete records with
//SHRINE_QUERY.HAS_BEEN_RUN = false for queries like the current one that ended up getting run.
//Invoking runQueryAdapter.processRequest() will add correct values to the DB for the
//actually-got-run query.
dao.deleteQueryResultsFor(queryId)
dao.deleteQuery(queryId)
runQueryAdapter.processRequest(newBroadcastMessage)
}
}
case None => ErrorResponse(s"Couldn't find query qith networkQueryId '${}'")
}
}
}
\ No newline at end of file
diff --git a/adapter/adapter-service/src/test/scala/net/shrine/adapter/CrcInvocationExceptionTest.scala b/adapter/adapter-service/src/test/scala/net/shrine/adapter/CrcInvocationExceptionTest.scala
index 6c6d3f489..138419249 100644
--- a/adapter/adapter-service/src/test/scala/net/shrine/adapter/CrcInvocationExceptionTest.scala
+++ b/adapter/adapter-service/src/test/scala/net/shrine/adapter/CrcInvocationExceptionTest.scala
@@ -1,45 +1,45 @@
package net.shrine.adapter
import net.shrine.util.ShouldMatchersForJUnit
import org.junit.Test
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.RunQueryRequest
/**
* @author clint
- * @date Oct 23, 2014
+ * @since Oct 23, 2014
*/
final class CrcInvocationExceptionTest extends ShouldMatchersForJUnit {
@Test
def testApply: Unit = {
import scala.concurrent.duration._
val authn = AuthenticationInfo("d", "p", Credential("alksfh", false))
val rootCause = new Exception with scala.util.control.NoStackTrace
val url = "http://example.com"
val deleteReq = DeleteQueryRequest("project-id", 1.minute, authn, 12345L)
- val runQueryReq = RunQueryRequest("project-id", 1.minute, authn, 123245L, None, Set.empty, null)
+ val runQueryReq = RunQueryRequest("project-id", 1.minute, authn, 123245L, None, None, Set.empty, null)
{
val e = CrcInvocationException(url, deleteReq, rootCause)
e.invokedUrl should equal(url)
e.rootCause should equal(rootCause)
e.request should equal(deleteReq)
}
{
val e = CrcInvocationException(url, runQueryReq, rootCause)
e.invokedUrl should equal(url)
e.rootCause should equal(rootCause)
e.request should equal(runQueryReq.elideAuthenticationInfo)
}
}
}
\ No newline at end of file
diff --git a/adapter/adapter-service/src/test/scala/net/shrine/adapter/RunQueryAdapterTest.scala b/adapter/adapter-service/src/test/scala/net/shrine/adapter/RunQueryAdapterTest.scala
index 7f1f4522f..a34182755 100644
--- a/adapter/adapter-service/src/test/scala/net/shrine/adapter/RunQueryAdapterTest.scala
+++ b/adapter/adapter-service/src/test/scala/net/shrine/adapter/RunQueryAdapterTest.scala
@@ -1,961 +1,962 @@
package net.shrine.adapter
import scala.concurrent.duration.DurationInt
import org.junit.Test
import net.shrine.util.ShouldMatchersForJUnit
import ObfuscatorTest.within3
import net.shrine.adapter.dao.AdapterDao
import net.shrine.adapter.dao.squeryl.AbstractSquerylAdapterTest
import net.shrine.adapter.translators.ExpressionTranslator
import net.shrine.adapter.translators.QueryDefinitionTranslator
import net.shrine.client.HttpClient
import net.shrine.client.HttpResponse
import net.shrine.client.Poster
import net.shrine.protocol.{HiveCredentials, AuthenticationInfo, BroadcastMessage, CrcRequest, Credential, I2b2ResultEnvelope, QueryResult, RawCrcRunQueryResponse, ReadResultRequest, ReadResultResponse, ResultOutputType, RunQueryRequest, RunQueryResponse, ErrorResponse, BaseShrineResponse, DefaultBreakdownResultOutputTypes}
import net.shrine.protocol.RawCrcRunQueryResponse.toQueryResultMap
import net.shrine.protocol.DefaultBreakdownResultOutputTypes.PATIENT_AGE_COUNT_XML
import net.shrine.protocol.ResultOutputType.PATIENT_COUNT_XML
import net.shrine.protocol.DefaultBreakdownResultOutputTypes.PATIENT_GENDER_COUNT_XML
import net.shrine.protocol.DefaultBreakdownResultOutputTypes.PATIENT_RACE_COUNT_XML
import net.shrine.protocol.query.OccuranceLimited
import net.shrine.protocol.query.Or
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.util.XmlDateHelper
import net.shrine.util.XmlUtil
import scala.util.Success
import net.shrine.dao.squeryl.SquerylEntryPoint
import scala.concurrent.duration.Duration
import net.shrine.adapter.dao.model.ShrineError
import net.shrine.adapter.dao.model.QueryResultRow
/**
* @author Bill Simons
* @author Clint Gilbert
* @since 4/19/11
* @see http://cbmi.med.harvard.edu
*/
final class RunQueryAdapterTest extends AbstractSquerylAdapterTest with ShouldMatchersForJUnit {
private val queryDef = QueryDefinition("foo", Term("foo"))
private val broadcastMessageId = 1234563789L
private val queryId = 123L
private val expectedNetworkQueryId = 999L
private val expectedLocalMasterId = queryId.toString
private val masterId = 99L
private val instanceId = 456L
private val resultId = 42L
private val projectId = "projectId"
private val setSize = 17L
private val xmlResultId = 98765L
private val userId = "userId"
private val groupId = "groupId"
private val topicId = "some-topic-id-123-foo"
+ private val topicName = "Topic Name"
private val justCounts = Set(PATIENT_COUNT_XML)
private val now = XmlDateHelper.now
private val countQueryResult = QueryResult(resultId, instanceId, Some(PATIENT_COUNT_XML), setSize, Some(now), Some(now), None, QueryResult.StatusType.Finished, None)
private val dummyBreakdownData = Map("x" -> 99L, "y" -> 42L, "z" -> 3000L)
private val hiveCredentials = HiveCredentials("some-hive-domain", "hive-username", "hive-password", "hive-project")
private val authn = AuthenticationInfo("some-domain", "username", Credential("jksafhkjaf", false))
private val adapterLockoutThreshold = 99
private val altI2b2ErrorXml = XmlUtil.stripWhitespace {
1.12.4edu.harvard.i2b2.crc1.5i2b2 Hivei2b2_QueryTool0.2i2b2 Hive1i2b2Log informationDONEQuery result instance id 3126 not found
}.toString
@Test
def testProcessRawCrcRunQueryResponseCountQueryOnly: Unit = afterCreatingTables{
val outputTypes = Set(PATIENT_COUNT_XML)
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(Map("network" -> Set("local1a", "local1b"))))
val adapter = new RunQueryAdapter(
Poster("crc-url", null),
dao,
hiveCredentials,
translator,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = true,
breakdownTypes = DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
- val request = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), outputTypes, queryDef)
+ val request = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), Option(topicName), outputTypes, queryDef)
val networkAuthn = AuthenticationInfo("some-domain", "username", Credential("sadasdasdasd", false))
val broadcastMessage = BroadcastMessage(queryId, networkAuthn, request)
val rawRunQueryResponse = RawCrcRunQueryResponse(
queryId = queryId,
createDate = XmlDateHelper.now,
userId = request.authn.username,
groupId = request.authn.domain,
requestXml = request.queryDefinition,
queryInstanceId = 12345L,
singleNodeResults = toQueryResultMap(Seq(countQueryResult)))
val resp = adapter.processRawCrcRunQueryResponse(networkAuthn, request, rawRunQueryResponse).asInstanceOf[RunQueryResponse]
resp should not be (null)
//Validate the response
resp.createDate should not be(null)
resp.groupId should be(request.authn.domain)
resp.userId should be(request.authn.username)
resp.queryId should be(queryId)
resp.queryInstanceId should be(12345L)
resp.requestXml should equal(request.queryDefinition)
(countQueryResult eq resp.singleNodeResult) should be(false)
within3(resp.singleNodeResult.setSize, countQueryResult.setSize) should be(true)
resp.singleNodeResult.resultType.get should equal(PATIENT_COUNT_XML)
resp.singleNodeResult.breakdowns should equal(Map.empty)
//validate the DB
val expectedNetworkTerm = queryDef.expr.get.asInstanceOf[Term]
//We should have one row in the shrine_query table, for the query just performed
val Seq(queryRow) = list(queryRows)
{
queryRow.dateCreated should not be (null)
queryRow.domain should equal(request.authn.domain)
queryRow.name should equal(queryDef.name)
queryRow.localId should equal(expectedLocalMasterId)
queryRow.networkId should equal(expectedNetworkQueryId)
queryRow.username should equal(authn.username)
queryRow.queryDefinition.expr.get should equal(expectedNetworkTerm)
}
//We should have one row in the count_result table, with the right obfuscated value, which is within the expected amount from the original count
val Seq(countRow) = list(countResultRows)
{
countRow.creationDate should not be (null)
countRow.originalValue should equal(countQueryResult.setSize)
within3(countRow.obfuscatedValue, countRow.originalValue) should be(true)
}
}
@Test
def testProcessRawCrcRunQueryResponseCountAndBreakdownQuery: Unit = afterCreatingTables {
val allBreakdownTypes = DefaultBreakdownResultOutputTypes.toSet
val breakdownTypes = Seq(PATIENT_GENDER_COUNT_XML)
val outputTypes = Set(PATIENT_COUNT_XML) ++ breakdownTypes
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(Map("network" -> Set("local1a", "local1b"))))
- val request = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), outputTypes, queryDef)
+ val request = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), Option(topicName), outputTypes, queryDef)
val networkAuthn = AuthenticationInfo("some-domain", "username", Credential("sadasdasdasd", false))
val broadcastMessage = BroadcastMessage(queryId, networkAuthn, request)
val breakdownQueryResults = breakdownTypes.zipWithIndex.map {
case (rt, i) =>
countQueryResult.withId(resultId + i + 1).withResultType(rt)
}
val singleNodeResults = toQueryResultMap(countQueryResult +: breakdownQueryResults)
val rawRunQueryResponse = RawCrcRunQueryResponse(
queryId = queryId,
createDate = XmlDateHelper.now,
userId = request.authn.username,
groupId = request.authn.domain,
requestXml = request.queryDefinition,
queryInstanceId = 12345L,
singleNodeResults = singleNodeResults)
//Set up our mock CRC
val poster = Poster("crc-url", new HttpClient {
def post(input: String, url: String): HttpResponse = HttpResponse.ok {
(RunQueryRequest.fromI2b2String(allBreakdownTypes)(input) orElse ReadResultRequest.fromI2b2String(allBreakdownTypes)(input)).get match {
case runQueryReq: RunQueryRequest => rawRunQueryResponse.toI2b2String
case readResultReq: ReadResultRequest => ReadResultResponse(xmlResultId = 42L, metadata = breakdownQueryResults.head, data = I2b2ResultEnvelope(PATIENT_GENDER_COUNT_XML, dummyBreakdownData)).toI2b2String
case _ => sys.error(s"Unknown request: '$input'") //Fail loudly
}
}
})
val adapter = new RunQueryAdapter(
poster,
dao,
hiveCredentials,
translator,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = true,
breakdownTypes = DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
val resp = adapter.processRawCrcRunQueryResponse(networkAuthn, request, rawRunQueryResponse).asInstanceOf[RunQueryResponse]
resp should not be (null)
//Validate the response
resp.createDate should not be(null)
resp.groupId should be(request.authn.domain)
resp.userId should be(request.authn.username)
resp.queryId should be(queryId)
resp.queryInstanceId should be(12345L)
resp.requestXml should equal(request.queryDefinition)
(countQueryResult eq resp.singleNodeResult) should be(false)
within3(resp.singleNodeResult.setSize, countQueryResult.setSize) should be(true)
resp.singleNodeResult.resultType.get should equal(PATIENT_COUNT_XML)
resp.singleNodeResult.breakdowns.keySet should equal(Set(PATIENT_GENDER_COUNT_XML))
val breakdownEnvelope = resp.singleNodeResult.breakdowns.values.head
breakdownEnvelope.resultType should equal(PATIENT_GENDER_COUNT_XML)
breakdownEnvelope.data.keySet should equal(dummyBreakdownData.keySet)
//All breakdowns are obfuscated
for {
(key, value) <- breakdownEnvelope.data
} {
within3(value, dummyBreakdownData(key)) should be(true)
}
//validate the DB
val expectedNetworkTerm = queryDef.expr.get.asInstanceOf[Term]
//We should have one row in the shrine_query table, for the query just performed
val Seq(queryRow) = list(queryRows)
{
queryRow.dateCreated should not be (null)
queryRow.domain should equal(request.authn.domain)
queryRow.name should equal(queryDef.name)
queryRow.localId should equal(expectedLocalMasterId)
queryRow.networkId should equal(expectedNetworkQueryId)
queryRow.username should equal(authn.username)
queryRow.queryDefinition.expr.get should equal(expectedNetworkTerm)
}
//We should have one row in the count_result table, with the right obfuscated value, which is within the expected amount from the original count
val Seq(countRow) = list(countResultRows)
{
countRow.creationDate should not be (null)
countRow.originalValue should equal(countQueryResult.setSize)
within3(countRow.obfuscatedValue, countRow.originalValue) should be(true)
}
val breakdownRows @ Seq(xRow, yRow, zRow) = list(breakdownResultRows)
breakdownRows.map(_.dataKey).toSet should equal(dummyBreakdownData.keySet)
within3(xRow.obfuscatedValue, xRow.originalValue) should be(true)
xRow.originalValue should be(dummyBreakdownData(xRow.dataKey))
within3(yRow.obfuscatedValue, yRow.originalValue) should be(true)
yRow.originalValue should be(dummyBreakdownData(yRow.dataKey))
within3(zRow.obfuscatedValue, zRow.originalValue) should be(true)
zRow.originalValue should be(dummyBreakdownData(zRow.dataKey))
}
//NB: See https://open.med.harvard.edu/jira/browse/SHRINE-745
@Test
def testParseAltErrorXml {
val adapter = new RunQueryAdapter(
Poster("crc-url", null),
null,
hiveCredentials,
null,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = false,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
val resp = adapter.parseShrineErrorResponseWithFallback(altI2b2ErrorXml).asInstanceOf[ErrorResponse]
resp should not be (null)
resp.errorMessage should be("Query result instance id 3126 not found")
}
@Test
def testParseErrorXml {
val xml = {
1.12.4edu.harvard.i2b2.crc1.4i2b2 Hivei2b2web1.4i2b2 Hive1DemoLog informationMessage error connecting Project Management celladmin00CRC_QRY_runQueryInstance_fromQueryDefinitionAge010012Age\\i2b2\i2b2\Demographics\Age\concept_dimensionconcept_path\i2b2\Demographics\Age\Tconcept_cdfalse
}.toString
val adapter = new RunQueryAdapter(
Poster("crc-url", null),
null,
hiveCredentials,
null,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = true,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
val resp = adapter.parseShrineErrorResponseWithFallback(xml).asInstanceOf[ErrorResponse]
resp should not be (null)
resp.errorMessage should not be ("")
}
@Test
def testObfuscateBreakdowns {
val breakdown1 = I2b2ResultEnvelope(PATIENT_AGE_COUNT_XML, Map.empty)
val breakdown2 = I2b2ResultEnvelope(PATIENT_GENDER_COUNT_XML, Map("foo" -> 123, "bar" -> 345))
val breakdown3 = I2b2ResultEnvelope(PATIENT_RACE_COUNT_XML, Map("x" -> 999, "y" -> 888))
val original = Map.empty ++ Seq(breakdown1, breakdown2, breakdown3).map(env => (env.resultType, env))
val obfuscated = RunQueryAdapter.obfuscateBreakdowns(original)
original.keySet should equal(obfuscated.keySet)
original.keySet.forall(resultType => original(resultType).data.keySet == obfuscated(resultType).data.keySet) should be(true)
val localTerms = Set("local1a", "local1b")
for {
(resultType, origBreakdown) <- original
mappings = Map("network" -> localTerms)
translator = new QueryDefinitionTranslator(new ExpressionTranslator(mappings))
obfscBreakdown <- obfuscated.get(resultType)
key <- origBreakdown.data.keySet
} {
(origBreakdown eq obfscBreakdown) should be(false)
ObfuscatorTest.within3(origBreakdown.data(key), obfscBreakdown.data(key)) should be(true)
}
}
@Test
def testTranslateNetworkToLocalDoesntLeakCredentialsViaException: Unit = {
val mappings = Map.empty[String, Set[String]]
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(mappings))
val adapter = new RunQueryAdapter(
Poster("crc-url", MockHttpClient),
null,
null,
translator,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = true,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
val queryDefinition = QueryDefinition("foo", Term("blah"))
val authn = AuthenticationInfo("d", "u", Credential("p", false))
- val req = RunQueryRequest("projectId", Duration.Inf, authn, 12345L, None, Set.empty, queryDef)
+ val req = RunQueryRequest("projectId", Duration.Inf, authn, 12345L, None, None, Set.empty, queryDef)
try {
adapter.translateNetworkToLocal(req)
fail("Expected an AdapterMappingException")
} catch {
case e: AdapterMappingException => {
e.getMessage.contains(authn.rawToString) should be(false)
e.getMessage.contains(AuthenticationInfo.elided.toString) should be(true)
}
}
}
@Test
def testTranslateQueryDefinitionXml {
val localTerms = Set("local1a", "local1b")
val mappings = Map("network" -> localTerms)
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(mappings))
val adapter = new RunQueryAdapter(
Poster("crc-url", MockHttpClient),
null,
null,
translator,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = true,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
val queryDefinition = QueryDefinition("10-17 years old@14:39:20", OccuranceLimited(1, Term("network")))
val newDef = adapter.conceptTranslator.translate(queryDefinition)
val expected = QueryDefinition("10-17 years old@14:39:20", Or(Term("local1a"), Term("local1b")))
newDef should equal(expected)
}
@Test
def testQueuedRegularCountQuery: Unit = afterCreatingTables {
val adapter = RunQueryAdapter(
Poster("crc-url", MockHttpClient),
dao,
null,
null,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = false,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
val networkAuthn = AuthenticationInfo("nd", "nu", Credential("np", false))
import scala.concurrent.duration._
- val req = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), Set(PATIENT_COUNT_XML), queryDef)
+ val req = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), Option(topicName), Set(PATIENT_COUNT_XML), queryDef)
val broadcastMessage = BroadcastMessage(queryId, networkAuthn, req)
val resp = adapter.processRequest(broadcastMessage).asInstanceOf[RunQueryResponse]
resp.groupId should equal(networkAuthn.domain)
resp.createDate should not be (null) // :\
resp.queryId should equal(-1L)
resp.queryInstanceId should equal(-1L)
resp.requestXml should equal(queryDef)
resp.userId should equal(networkAuthn.username)
resp.singleNodeResult.breakdowns should equal(Map.empty)
resp.singleNodeResult.description.isDefined should be(true)
resp.singleNodeResult.elapsed should equal(Some(0L))
resp.singleNodeResult.endDate.isDefined should be(true)
resp.singleNodeResult.startDate.isDefined should be(true)
resp.singleNodeResult.instanceId should equal(-1L)
resp.singleNodeResult.isError should be(false)
resp.singleNodeResult.resultId should equal(-1L)
resp.singleNodeResult.resultType should be(Some(PATIENT_COUNT_XML))
resp.singleNodeResult.setSize should equal(-1L)
resp.singleNodeResult.statusMessage.isDefined should be(true)
resp.singleNodeResult.statusType should be(QueryResult.StatusType.Held)
resp.singleNodeResult.endDate.isDefined should be(true)
val Some(storedQuery) = dao.findQueryByNetworkId(expectedNetworkQueryId)
storedQuery.dateCreated should not be (null) // :\
storedQuery.domain should equal(networkAuthn.domain)
storedQuery.hasBeenRun should equal(false)
storedQuery.isFlagged should equal(false)
storedQuery.localId should equal(-1L.toString)
storedQuery.name should equal(queryDef.name)
storedQuery.networkId should equal(expectedNetworkQueryId)
storedQuery.queryDefinition should equal(queryDef)
storedQuery.username should equal(networkAuthn.username)
}
private def doTestRegularCountQuery(status: QueryResult.StatusType, count: Long) = afterCreatingTables {
require(!status.isError)
val countQueryResultToUse = countQueryResult.copy(statusType = status, setSize = count)
val outputTypes = justCounts
val resp = doQuery(outputTypes) {
import RawCrcRunQueryResponse.toQueryResultMap
RawCrcRunQueryResponse(queryId, now, userId, groupId, queryDef, instanceId, toQueryResultMap(Seq(countQueryResultToUse))).toI2b2String
}.asInstanceOf[RunQueryResponse]
doBasicRunQueryResponseTest(resp)
val firstResult = resp.results.head
resp.results should equal(Seq(firstResult))
val Some(savedQuery) = dao.findResultsFor(expectedNetworkQueryId)
savedQuery.wasRun should equal(true)
savedQuery.isFlagged should equal(false)
savedQuery.networkQueryId should equal(expectedNetworkQueryId)
savedQuery.breakdowns should equal(Nil)
savedQuery.count.creationDate should not be (null)
savedQuery.count.localId should equal(countQueryResultToUse.resultId)
//savedQuery.count.resultId should equal(resultId) TODO: REVISIT
savedQuery.count.statusType should equal(status)
if (status.isDone && !status.isError) {
savedQuery.count.data.get.startDate should not be (null)
savedQuery.count.data.get.endDate should not be (null)
savedQuery.count.data.get.originalValue should be(count)
ObfuscatorTest.within3(savedQuery.count.data.get.obfuscatedValue, count) should be(true)
} else {
savedQuery.count.data should be(None)
}
}
@Test
def testRegularCountQuery = doTestRegularCountQuery(QueryResult.StatusType.Finished, countQueryResult.setSize)
@Test
def testRegularCountQueryComesBackProcessing = doTestRegularCountQuery(QueryResult.StatusType.Processing, -1L)
@Test
def testRegularCountQueryComesBackQueued = doTestRegularCountQuery(QueryResult.StatusType.Queued, -1L)
@Test
def testRegularCountQueryComesBackError = afterCreatingTables {
val errorQueryResult = QueryResult.errorResult(Some("some-description"), "some-status-message")
val outputTypes = justCounts
val resp = doQuery(outputTypes) {
import RawCrcRunQueryResponse.toQueryResultMap
RawCrcRunQueryResponse(queryId, now, userId, groupId, queryDef, instanceId, toQueryResultMap(Seq(errorQueryResult))).toI2b2String
}
doBasicRunQueryResponseTest(resp)
//TODO: Why are status and description messages from CRC dropped when unmarshalling QueryResults?
//resp.results should equal(Seq(errorQueryResult))
resp.asInstanceOf[RunQueryResponse].results.head.statusType should be(QueryResult.StatusType.Error)
dao.findResultsFor(expectedNetworkQueryId) should be(None)
val Some(savedQueryRow) = dao.findQueryByNetworkId(expectedNetworkQueryId)
val Seq(queryResultRow: QueryResultRow) = {
import SquerylEntryPoint._
implicit val breakdownTypes = DefaultBreakdownResultOutputTypes.toSet
inTransaction {
from(tables.queryResults) { row =>
where(row.queryId === savedQueryRow.id).
select(row.toQueryResultRow)
}.toSeq
}
}
val Seq(errorRow: ShrineError) = {
import SquerylEntryPoint._
inTransaction {
from(tables.errorResults) { row =>
where(row.resultId === queryResultRow.id).
select(row.toShrineError)
}.toSeq
}
}
errorRow should not be (null)
//TODO:
//errorRow.message should equal(errorQueryResult.statusMessage)
}
private def doTestBreakdownsAreObfuscated(result: QueryResult): Unit = {
result.breakdowns.values.map(_.data).foreach { actualBreakdowns =>
actualBreakdowns.keySet should equal(dummyBreakdownData.keySet)
for {
breakdownName <- actualBreakdowns.keySet
} {
within3(actualBreakdowns(breakdownName), dummyBreakdownData(breakdownName)) should be(true)
}
}
}
@Test
def testGetBreakdownsWithRegularCountQuery {
val breakdowns = DefaultBreakdownResultOutputTypes.values.map(breakdownFor)
val resp = doTestGetBreakdowns(breakdowns)
val firstResult = resp.results.head
firstResult.resultType should equal(Some(PATIENT_COUNT_XML))
firstResult.setSize should equal(setSize)
firstResult.description should equal(None)
firstResult.breakdowns.keySet should equal(DefaultBreakdownResultOutputTypes.toSet)
//NB: Verify that breakdowns are obfuscated
doTestBreakdownsAreObfuscated(firstResult)
resp.results.size should equal(1)
}
@Test
def testGetBreakdownsSomeFailures {
val resultTypesExpectedToSucceed = Seq(PATIENT_AGE_COUNT_XML, PATIENT_GENDER_COUNT_XML)
val breakdowns = resultTypesExpectedToSucceed.map(breakdownFor)
val resp = doTestGetBreakdowns(breakdowns)
val firstResult = resp.results.head
firstResult.resultType should equal(Some(PATIENT_COUNT_XML))
firstResult.setSize should equal(setSize)
firstResult.description should equal(None)
firstResult.breakdowns.keySet should equal(resultTypesExpectedToSucceed.toSet)
//NB: Verify that breakdowns are obfuscated
doTestBreakdownsAreObfuscated(firstResult)
resp.results.size should equal(1)
}
@Test
def testErrorResponsesArePassedThrough: Unit = {
val errorResponse = ErrorResponse("blarg!")
val resp = doQuery(Set(PATIENT_COUNT_XML)) {
errorResponse.toI2b2String
}
resp should equal(errorResponse)
}
private def breakdownFor(resultType: ResultOutputType) = I2b2ResultEnvelope(resultType, dummyBreakdownData)
private def doTestGetBreakdowns(successfulBreakdowns: Seq[I2b2ResultEnvelope]): RunQueryResponse = {
val outputTypes = justCounts ++ DefaultBreakdownResultOutputTypes.toSet
val resp = doQueryThatReturnsSpecifiedBreakdowns(outputTypes, successfulBreakdowns)
doBasicRunQueryResponseTest(resp)
resp
}
private def doBasicRunQueryResponseTest(r: BaseShrineResponse) {
val resp = r.asInstanceOf[RunQueryResponse]
resp.createDate should equal(now)
resp.groupId should equal(groupId)
resp.queryId should equal(queryId)
resp.queryInstanceId should equal(instanceId)
resp.queryName should equal(queryDef.name)
resp.requestXml should equal(queryDef)
}
private def doQueryThatReturnsSpecifiedBreakdowns(outputTypes: Set[ResultOutputType], successfulBreakdowns: Seq[I2b2ResultEnvelope]): RunQueryResponse = afterCreatingTablesReturn {
val breakdownQueryResults = DefaultBreakdownResultOutputTypes.values.zipWithIndex.map {
case (rt, i) =>
countQueryResult.withId(resultId + i + 1).withResultType(rt)
}
//Need this rigamarole to ensure that resultIds line up such that the type of breakdown the adapter asks for
//(PATIENT_AGE_COUNT_XML, etc) is what the mock HttpClient actually returns. Here, we build up maps of QueryResults
//and I2b2ResultEnvelopes, keyed on resultIds generated in the previous expression, to use to look up values to use
//to build ReadResultResponses
val successfulBreakdownsByType = successfulBreakdowns.map(e => e.resultType -> e).toMap
val successfulBreakdownTypes = successfulBreakdownsByType.keySet
val breakdownQueryResultsByResultId = breakdownQueryResults.collect { case qr if successfulBreakdownTypes(qr.resultType.get) => qr.resultId -> qr }.toMap
val breakdownsToBeReturnedByResultId = breakdownQueryResultsByResultId.map {
case (resultId, queryResult) => (resultId, successfulBreakdownsByType(queryResult.resultType.get))
}
val expectedLocalTerm = Term("bar")
val httpClient = new HttpClient {
override def post(input: String, url: String): HttpResponse = {
val resp = CrcRequest.fromI2b2String(DefaultBreakdownResultOutputTypes.toSet)(input) match {
case Success(req: RunQueryRequest) => {
//NB: Terms should be translated
req.queryDefinition.expr.get should equal(expectedLocalTerm)
//Credentials should be "translated"
req.authn.username should equal(hiveCredentials.username)
req.authn.domain should equal(hiveCredentials.domain)
//I2b2 Project ID should be translated
req.projectId should equal(hiveCredentials.projectId)
val queryResultMap = RawCrcRunQueryResponse.toQueryResultMap(countQueryResult +: breakdownQueryResults)
RawCrcRunQueryResponse(queryId, now, "userId", "groupId", queryDef, instanceId, queryResultMap)
}
//NB: return a ReadResultResponse with new breakdown data each time, but will throw if the asked-for breakdown
//is not one of the ones passed to the enclosing method, simulating an error calling the CRC
case Success(req: ReadResultRequest) => {
val resultId = req.localResultId.toLong
ReadResultResponse(xmlResultId, breakdownQueryResultsByResultId(resultId), breakdownsToBeReturnedByResultId(resultId))
}
case _ => ??? //fail loudly
}
HttpResponse.ok(resp.toI2b2String)
}
}
val result = doQuery(outputTypes, dao, httpClient)
validateDb(successfulBreakdowns, breakdownQueryResultsByResultId)
result.asInstanceOf[RunQueryResponse]
}
private def validateDb(breakdownsReturned: Seq[I2b2ResultEnvelope], breakdownQueryResultsByResultId: Map[Long, QueryResult]) {
val expectedNetworkTerm = Term("foo")
//We should have one row in the shrine_query table, for the query just performed
val queryRow = first(queryRows)
{
queryRow.dateCreated should not be (null)
queryRow.domain should equal(authn.domain)
queryRow.name should equal(queryDef.name)
queryRow.localId should equal(expectedLocalMasterId)
queryRow.networkId should equal(expectedNetworkQueryId)
queryRow.username should equal(authn.username)
queryRow.queryDefinition.expr.get should equal(expectedNetworkTerm)
}
list(queryRows).size should equal(1)
//We should have one row in the count_result table, with the right obfuscated value, which is within the expected amount from the original count
val countRow = first(countResultRows)
{
countRow.creationDate should not be (null)
countRow.originalValue should equal(countQueryResult.setSize)
within3(countRow.obfuscatedValue, countQueryResult.setSize) should be(true)
within3(countRow.obfuscatedValue, countRow.originalValue) should be(true)
}
list(countResultRows).size should equal(1)
//We should have 5 rows in the query_result table, one for the count result and one for each of the 4 requested breakdown types
val queryResults = list(queryResultRows)
{
val countQueryResultRow = queryResults.find(_.resultType == PATIENT_COUNT_XML).get
countQueryResultRow.localId should equal(countQueryResult.resultId)
countQueryResultRow.queryId should equal(queryRow.id)
val resultIdsByResultType = breakdownQueryResultsByResultId.map { case (resultId, queryResult) => queryResult.resultType.get -> resultId }.toMap
for (breakdownType <- DefaultBreakdownResultOutputTypes.values) {
val breakdownQueryResultRow = queryResults.find(_.resultType == breakdownType).get
breakdownQueryResultRow.queryId should equal(queryRow.id)
//We'll have a result id if this breakdown type didn't fail
if (resultIdsByResultType.contains(breakdownQueryResultRow.resultType)) {
breakdownQueryResultRow.localId should equal(resultIdsByResultType(breakdownQueryResultRow.resultType))
}
}
}
queryResults.size should equal(5)
val returnedBreakdownTypes = breakdownsReturned.map(_.resultType).toSet
val notReturnedBreakdownTypes = DefaultBreakdownResultOutputTypes.toSet -- returnedBreakdownTypes
val errorResults = list(errorResultRows)
//We should have a row in the error_result table for each breakdown that COULD NOT be retrieved
{
for {
queryResult <- queryResults
if notReturnedBreakdownTypes.contains(queryResult.resultType)
resultType = queryResult.resultType
resultId = queryResult.id
} {
errorResults.find(_.resultId == resultId).isDefined should be(true)
}
}
errorResults.size should equal(notReturnedBreakdownTypes.size)
//We should have properly-obfuscated rows in the breakdown_result table for each of the breakdown types that COULD be retrieved
val breakdownResults = list(breakdownResultRows)
val bdrs = breakdownResults.toIndexedSeq
{
for {
queryResult <- queryResults
if returnedBreakdownTypes.contains(queryResult.resultType)
resultType = queryResult.resultType
resultId = queryResult.id
} {
//Find all the rows for a particular breakdown type
val rowsWithType = breakdownResults.filter(_.resultId == resultId)
//Combining the rows should give the expected dummy data
rowsWithType.map(row => row.dataKey -> row.originalValue).toMap should equal(dummyBreakdownData)
for (breakdownRow <- rowsWithType) {
within3(breakdownRow.obfuscatedValue, dummyBreakdownData(breakdownRow.dataKey)) should be(true)
}
}
}
}
private def doQuery(outputTypes: Set[ResultOutputType])(i2b2XmlToReturn: => String): BaseShrineResponse = {
doQuery(outputTypes, dao, MockHttpClient(i2b2XmlToReturn))
}
private def doQuery(outputTypes: Set[ResultOutputType], adapterDao: AdapterDao, httpClient: HttpClient): BaseShrineResponse = {
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(Map("foo" -> Set("bar"))))
//NB: Don't obfuscate, for simpler testing
val adapter = new RunQueryAdapter(
Poster("crc-url", httpClient),
adapterDao,
hiveCredentials,
translator,
adapterLockoutThreshold,
doObfuscation = false,
runQueriesImmediately = true,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
import scala.concurrent.duration._
- val req = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), outputTypes, queryDef)
+ val req = RunQueryRequest(projectId, 1.second, authn, expectedNetworkQueryId, Option(topicId), Option(topicName), outputTypes, queryDef)
val networkAuthn = AuthenticationInfo("some-domain", "username", Credential("sadasdasdasd", false))
val broadcastMessage = BroadcastMessage(queryId, networkAuthn, req)
adapter.processRequest(broadcastMessage)
}
}
\ No newline at end of file
diff --git a/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceEndToEndJaxrsTest.scala b/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceEndToEndJaxrsTest.scala
index 45d289aa5..f7fa9d870 100644
--- a/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceEndToEndJaxrsTest.scala
+++ b/adapter/adapter-service/src/test/scala/net/shrine/adapter/service/I2b2AdminResourceEndToEndJaxrsTest.scala
@@ -1,188 +1,188 @@
package net.shrine.adapter.service
import org.junit.Test
import net.shrine.adapter.HasI2b2AdminDao
import net.shrine.protocol.{HiveCredentials, ReadI2b2AdminPreviousQueriesRequest, ReadI2b2AdminQueryingUsersRequest, ReadI2b2AdminQueryingUsersResponse, I2b2AdminUserWithRole, ErrorResponse, RunHeldQueryRequest, RunQueryResponse, RunQueryRequest, ResultOutputType, QueryResult, BroadcastMessage, AuthenticationInfo, Credential, DefaultBreakdownResultOutputTypes}
import net.shrine.client.Poster
import net.shrine.adapter.RunQueryAdapter
import net.shrine.adapter.translators.QueryDefinitionTranslator
import net.shrine.adapter.translators.ExpressionTranslator
import net.shrine.client.HttpClient
import net.shrine.client.HttpResponse
import net.shrine.protocol.query.Term
import scala.util.Success
import net.shrine.util.XmlDateHelper
import net.shrine.protocol.query.QueryDefinition
/**
* @author clint
- * @date Apr 12, 2013
+ * @since Apr 12, 2013
*
* NB: Ideally we would extend JerseyTest here, but since we have to extend AbstractDependencyInjectionSpringContextTests,
* we get into a diamond-problem when extending JerseyTest as well, even when both of them are extended by shim traits.
*
* We work around this issue by mising in JerseyTestCOmponent, which brings in a JerseyTest by composition, and ensures
* that it is set up and torn down properly.
*/
final class I2b2AdminResourceEndToEndJaxrsTest extends AbstractI2b2AdminResourceJaxrsTest with HasI2b2AdminDao {
private[this] val dummyUrl = "http://example.com"
private[this] val dummyText = "This is dummy text"
private[this] val dummyMasterId = 873456L
private[this] val dummyInstanceId = 99L
private[this] val dummyResultId = 42L
private[this] val dummySetSize = 12345L
private[this] val networkAuthn = AuthenticationInfo("network-domain", "network-username", Credential("network-password", false))
private lazy val runQueryAdapter: RunQueryAdapter = {
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(Map("n1" -> Set("l1"))))
val poster = new Poster(dummyUrl, new HttpClient {
override def post(input: String, url: String): HttpResponse = {
RunQueryRequest.fromI2b2String(DefaultBreakdownResultOutputTypes.toSet)(input) match {
case Success(req) => {
val queryResult = QueryResult(dummyResultId, dummyInstanceId, Some(ResultOutputType.PATIENT_COUNT_XML), dummySetSize, Some(XmlDateHelper.now), Some(XmlDateHelper.now), Some("desc"), QueryResult.StatusType.Finished, Some("status"))
val resp = RunQueryResponse(dummyMasterId, XmlDateHelper.now, networkAuthn.username, networkAuthn.domain, req.queryDefinition, 123L, queryResult)
HttpResponse.ok(resp.toI2b2String)
}
case _ => ???
}
}
})
RunQueryAdapter(
poster,
dao,
HiveCredentials("d", "u", "pwd", "pid"),
translator,
1000,
false,
true,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
}
override def makeHandler = new I2b2AdminService(dao, i2b2AdminDao, Poster(dummyUrl, AlwaysAuthenticatesMockPmHttpClient), runQueryAdapter)
@Test
def testReadQueryDefinition = afterLoadingTestData {
doTestReadQueryDefinition(networkQueryId1, Some((queryName1, queryDef1)))
}
@Test
def testReadQueryDefinitionUnknownQueryId = afterLoadingTestData {
doTestReadQueryDefinition(87134682364L, None)
}
import ReadI2b2AdminPreviousQueriesRequest.{Username, Category, SortOrder}
import Username._
@Test
def testReadI2b2AdminPreviousQueries = afterLoadingTestData {
val searchString = queryName1
val maxResults = 123
val sortOrder = ReadI2b2AdminPreviousQueriesRequest.SortOrder.Ascending
val categoryToSearchWithin = ReadI2b2AdminPreviousQueriesRequest.Category.All
val searchStrategy = ReadI2b2AdminPreviousQueriesRequest.Strategy.Exact
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, All, searchString, maxResults, None, sortOrder, searchStrategy, categoryToSearchWithin)
doTestReadI2b2AdminPreviousQueries(request, Seq(queryMaster1))
}
@Test
def testReadI2b2AdminPreviousQueriesNoResultsExpected = afterLoadingTestData {
//A request that won't return anything
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, All, "askjdhakfgkafgkasf", 123, None)
doTestReadI2b2AdminPreviousQueries(request, Nil)
}
@Test
def testReadI2b2AdminPreviousQueriesExcludeUser: Unit = afterLoadingTestData {
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, Except(authn2.username), "", 10, None)
doTestReadI2b2AdminPreviousQueries(request, Seq(queryMaster2, queryMaster1))
}
@Test
def testReadI2b2AdminPreviousQueriesOnlyFlagged: Unit = afterLoadingTestData {
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, All, "", 10, None, categoryToSearchWithin = Category.Flagged)
doTestReadI2b2AdminPreviousQueries(request, Seq(queryMaster4, queryMaster1))
}
@Test
def testReadPreviousQueriesOnlyFlaggedExcludingUser: Unit = afterLoadingTestData {
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, Except(authn.username), "", 10, None, categoryToSearchWithin = Category.Flagged)
doTestReadI2b2AdminPreviousQueries(request, Seq(queryMaster4))
}
@Test
def testReadPreviousQueriesExcludingUserWithSearchString: Unit = afterLoadingTestData {
val request = ReadI2b2AdminPreviousQueriesRequest(projectId, waitTime, authn, All, queryName1, 10, None, categoryToSearchWithin = Category.Flagged)
doTestReadI2b2AdminPreviousQueries(request, Seq(queryMaster1))
}
@Test
def testReadI2b2QueryingUsers = afterLoadingTestData {
val request = ReadI2b2AdminQueryingUsersRequest(projectId, waitTime, authn, "foo")
val ReadI2b2AdminQueryingUsersResponse(users) = adminClient.readI2b2AdminQueryingUsers(request)
users.toSet should equal(Set(I2b2AdminUserWithRole(shrineProjectId, authn.username, "USER"), I2b2AdminUserWithRole(shrineProjectId, authn2.username, "USER")))
}
@Test
def testReadI2b2QueryingUsersNoResultsExpected = afterCreatingTables {
val request = ReadI2b2AdminQueryingUsersRequest(projectId, waitTime, authn, "foo")
val ReadI2b2AdminQueryingUsersResponse(users) = adminClient.readI2b2AdminQueryingUsers(request)
//DB is empty, so no users will be returned
users should equal(Nil)
}
@Test
def testRunHeldQueryUnknownQuery = afterCreatingTables {
val request = RunHeldQueryRequest(projectId, waitTime, authn, 12345L)
val resp = adminClient.runHeldQuery(request)
resp.isInstanceOf[ErrorResponse] should be(true)
}
@Test
def testRunHeldQueryKnownQuery = afterCreatingTables {
val networkQueryId = 12345L
val request = RunHeldQueryRequest(projectId, waitTime, authn, networkQueryId)
val queryName = "aslkdjasljkd"
val queryExpr = Term("n1")
- val runQueryReq = RunQueryRequest(projectId, waitTime, authn, networkQueryId, None, Set(ResultOutputType.PATIENT_COUNT_XML), QueryDefinition(queryName, queryExpr))
+ val runQueryReq = RunQueryRequest(projectId, waitTime, authn, networkQueryId, None, None, Set(ResultOutputType.PATIENT_COUNT_XML), QueryDefinition(queryName, queryExpr))
runQueryAdapter.copy(runQueriesImmediately = false).processRequest(BroadcastMessage(networkAuthn, runQueryReq))
val resp = adminClient.runHeldQuery(request)
val runQueryResp = resp.asInstanceOf[RunQueryResponse]
runQueryResp.createDate should not be(null)
runQueryResp.groupId should be(networkAuthn.domain)
runQueryResp.userId should equal(networkAuthn.username)
runQueryResp.queryId should equal(dummyMasterId)
runQueryResp.singleNodeResult.setSize should equal(dummySetSize)
runQueryResp.singleNodeResult.resultType should equal(Some(ResultOutputType.PATIENT_COUNT_XML)) //TODO
runQueryResp.requestXml.name should equal(queryName)
runQueryResp.requestXml.expr.get should equal(Term("l1"))
}
}
diff --git a/apps/admin-app/src/main/js/happy/happy-adapter.xml b/apps/admin-app/src/main/js/happy/happy-adapter.xml
index f46ee9b6a..613aaf0dd 100644
--- a/apps/admin-app/src/main/js/happy/happy-adapter.xml
+++ b/apps/admin-app/src/main/js/happy/happy-adapter.xml
@@ -1,13 +1,13 @@
NodeId(shrine-qa1)9 milliseconds
- Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),6623773019075051117,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
+ Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),6623773019075051117,None,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
\ No newline at end of file
diff --git a/apps/admin-app/src/main/js/happy/happy-all.xml b/apps/admin-app/src/main/js/happy/happy-all.xml
index 984177104..84178210a 100644
--- a/apps/admin-app/src/main/js/happy/happy-all.xml
+++ b/apps/admin-app/src/main/js/happy/happy-all.xml
@@ -1,220 +1,220 @@
1.20.0-SNAPSHOTUNKNOWNUnknown(not available)UNKNOWN_BRANCH2015-07-24 11:50:33/opt/shrine/shrine.keystoreJKSshrine-qa1
CN=shrine-qa1.hms.harvard.edu, OU=SHRINE, O=Harvard Medical School, L=Boston, ST=Massachusetts, C=US
14000929453842384735
CN=shrine-qa1.hms.harvard.edu, OU=SHRINE, O=Harvard Medical School, L=Boston, ST=Massachusetts, C=US
14000929453842384735shrine-qa4
https://shrine-qa4.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa2
https://shrine-qa2.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa3
https://shrine-qa3.hms.harvard.edu:6443/shrine/rest/adapter/requests
http://134.174.149.146/i2b2/services/QueryToolService/
http://134.174.149.146/i2b2/services/OntologyService/
trueshrine-qa4
https://shrine-qa4.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa2
https://shrine-qa2.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa3
https://shrine-qa3.hms.harvard.edu:6443/shrine/rest/adapter/requests
true4400shrine-qa4
https://shrine-qa4.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa2
https://shrine-qa2.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa3
https://shrine-qa3.hms.harvard.edu:6443/shrine/rest/adapter/requests
NodeId(shrine-qa1)12 milliseconds
- Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),4846597226961470790,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
+ Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),4846597226961470790,None,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
21919multi21918multi21917multi21916shrine21915shrine21914shrine21913ben21912ben21911multi21910ben69026293777567324332015-07-24T15:24:26.000-04:0018-34 years old@15:24:2261332469771101797502015-07-24T12:51:11.000-04:0018-34 years old@12:51:1082564228012151658462015-07-24T12:13:18.000-04:00Male@12:13:1485579026017089969342015-07-22T16:38:03.000-04:000-9 years old@16:37:4477771836566912314942015-07-14T13:23:41.000-04:00(008.00) Intest@13:23:3877396576547239859672015-07-06T17:37:02.000-04:00Chinese@17:37:046007796316694290472015-07-06T17:31:30.000-04:0018-34 years old@17:31:2638374299204131903232015-07-01T15:29:27.000-04:00Wampanoag@15:29:301647134675283450312015-07-01T14:32:45.000-04:00(008.00) Intest@00:02:5631038247353556373452015-07-01T14:18:50.000-04:00Female@23:48:56
\ No newline at end of file
diff --git a/apps/admin-app/src/main/resources/client/happy/happy-adapter.xml b/apps/admin-app/src/main/resources/client/happy/happy-adapter.xml
index f46ee9b6a..613aaf0dd 100644
--- a/apps/admin-app/src/main/resources/client/happy/happy-adapter.xml
+++ b/apps/admin-app/src/main/resources/client/happy/happy-adapter.xml
@@ -1,13 +1,13 @@
NodeId(shrine-qa1)9 milliseconds
- Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),6623773019075051117,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
+ Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),6623773019075051117,None,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
\ No newline at end of file
diff --git a/apps/admin-app/src/main/resources/client/happy/happy-all.xml b/apps/admin-app/src/main/resources/client/happy/happy-all.xml
index 984177104..84178210a 100644
--- a/apps/admin-app/src/main/resources/client/happy/happy-all.xml
+++ b/apps/admin-app/src/main/resources/client/happy/happy-all.xml
@@ -1,220 +1,220 @@
1.20.0-SNAPSHOTUNKNOWNUnknown(not available)UNKNOWN_BRANCH2015-07-24 11:50:33/opt/shrine/shrine.keystoreJKSshrine-qa1
CN=shrine-qa1.hms.harvard.edu, OU=SHRINE, O=Harvard Medical School, L=Boston, ST=Massachusetts, C=US
14000929453842384735
CN=shrine-qa1.hms.harvard.edu, OU=SHRINE, O=Harvard Medical School, L=Boston, ST=Massachusetts, C=US
14000929453842384735shrine-qa4
https://shrine-qa4.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa2
https://shrine-qa2.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa3
https://shrine-qa3.hms.harvard.edu:6443/shrine/rest/adapter/requests
http://134.174.149.146/i2b2/services/QueryToolService/
http://134.174.149.146/i2b2/services/OntologyService/
trueshrine-qa4
https://shrine-qa4.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa2
https://shrine-qa2.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa3
https://shrine-qa3.hms.harvard.edu:6443/shrine/rest/adapter/requests
true4400shrine-qa4
https://shrine-qa4.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa2
https://shrine-qa2.hms.harvard.edu:6443/shrine/rest/adapter/requests
shrine-qa3
https://shrine-qa3.hms.harvard.edu:6443/shrine/rest/adapter/requests
NodeId(shrine-qa1)12 milliseconds
- Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),4846597226961470790,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
+ Error mapping query terms from network to local forms. request: RunQueryRequest(Demo,3 minutes,AuthenticationInfo(*******,*******,Credential(*******,false)),4846597226961470790,None,None,Set(PATIENT_COUNT_XML),QueryDefinition(PDD,Some(OccuranceLimited(1,Term(\\SHRINE\SHRINE\Diagnoses\Mental Illness\Disorders usually diagnosed in infancy, childhood, or adolescence\Pervasive developmental disorders\Infantile autism, current or active state\))),Some(ANY),None,None,None,List()))
21919multi21918multi21917multi21916shrine21915shrine21914shrine21913ben21912ben21911multi21910ben69026293777567324332015-07-24T15:24:26.000-04:0018-34 years old@15:24:2261332469771101797502015-07-24T12:51:11.000-04:0018-34 years old@12:51:1082564228012151658462015-07-24T12:13:18.000-04:00Male@12:13:1485579026017089969342015-07-22T16:38:03.000-04:000-9 years old@16:37:4477771836566912314942015-07-14T13:23:41.000-04:00(008.00) Intest@13:23:3877396576547239859672015-07-06T17:37:02.000-04:00Chinese@17:37:046007796316694290472015-07-06T17:31:30.000-04:0018-34 years old@17:31:2638374299204131903232015-07-01T15:29:27.000-04:00Wampanoag@15:29:301647134675283450312015-07-01T14:32:45.000-04:00(008.00) Intest@00:02:5631038247353556373452015-07-01T14:18:50.000-04:00Female@23:48:56
\ No newline at end of file
diff --git a/apps/shrine-app/src/main/scala/net/shrine/happy/HappyShrineService.scala b/apps/shrine-app/src/main/scala/net/shrine/happy/HappyShrineService.scala
index e01ac140f..43957f93e 100644
--- a/apps/shrine-app/src/main/scala/net/shrine/happy/HappyShrineService.scala
+++ b/apps/shrine-app/src/main/scala/net/shrine/happy/HappyShrineService.scala
@@ -1,317 +1,318 @@
package net.shrine.happy
import net.shrine.log.Loggable
import net.shrine.wiring.ShrineConfig
import scala.concurrent.Await
import scala.util.Try
import scala.xml.Node
import scala.xml.NodeSeq
import net.shrine.adapter.dao.AdapterDao
import net.shrine.adapter.service.AdapterRequestHandler
import net.shrine.broadcaster.{IdAndUrl, AdapterClientBroadcaster}
import net.shrine.service.dao.AuditDao
import net.shrine.client.Poster
import net.shrine.crypto.KeyStoreCertCollection
import net.shrine.crypto.Signer
import net.shrine.i2b2.protocol.pm.GetUserConfigurationRequest
import net.shrine.i2b2.protocol.pm.HiveConfig
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.BroadcastMessage
import net.shrine.protocol.Credential
import net.shrine.protocol.Failure
import net.shrine.protocol.NodeId
import net.shrine.protocol.Result
import net.shrine.protocol.ResultOutputType
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.Timeout
import net.shrine.protocol.query.OccuranceLimited
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.util.{StackTrace, Versions, XmlUtil}
import net.shrine.ont.data.OntologyMetadata
import net.shrine.config.mappings.AdapterMappings
import net.shrine.crypto.SigningCertStrategy
/**
* @author Bill Simons
* @since 6/20/11
* @see http://cbmi.med.harvard.edu
* @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @see http://www.gnu.org/licenses/lgpl.html
*/
final class HappyShrineService(
config: ShrineConfig,
certCollection: KeyStoreCertCollection,
signer: Signer,
pmPoster: Poster,
ontologyMetadata: OntologyMetadata,
adapterMappings: Option[AdapterMappings],
auditDaoOption: Option[AuditDao],
adapterDaoOption: Option[AdapterDao],
broadcasterOption: Option[AdapterClientBroadcaster],
adapterOption: Option[AdapterRequestHandler]) extends HappyShrineRequestHandler with Loggable {
info("Happy service initialized")
private val notAnAdapter = ""
private val notAHub = ""
private val domain = "happy"
private val username = "happy"
private val networkAuthn = AuthenticationInfo(domain, username, Credential("", isToken = false))
override def keystoreReport: String = {
val myCertId = certCollection.myCertId
def unpack(name: Option[String]) = name.getOrElse("Unknown")
XmlUtil.stripWhitespace {
{ config.keystoreDescriptor.file }{ config.keystoreDescriptor.keyStoreType }{ config.keystoreDescriptor.privateKeyAlias.getOrElse("unspecified") }
{
myCertId.map { myId =>
{ unpack(myId.name) }{ myId.serial }
}.getOrElse {
}
}
{
certCollection.ids.map { certId =>
{ unpack(certId.name) }{ certId.serial }
}
}
}.toString
}
private def nodeListAsXml: Iterable[Node] = config.hubConfig match {
case None => Nil
case Some(hubConfig) => hubConfig.downstreamNodes.map {
case IdAndUrl(NodeId(nodeName), nodeUrl) => {
{ nodeName }{ nodeUrl }
}
}
}
override def routingReport: String = XmlUtil.stripWhitespace {
{ nodeListAsXml }
}.toString
override def hiveReport: String = {
val report = for {
adapterConfig <- config.adapterConfig
} yield {
val credentials = config.pmHiveCredentials
val pmRequest = GetUserConfigurationRequest(credentials.toAuthenticationInfo)
val response = pmPoster.post(pmRequest.toI2b2String)
HiveConfig.fromI2b2(response.body).toXmlString
}
report.getOrElse(notAnAdapter)
}
private def failureToXml(failure: Failure): NodeSeq = {
{ failure.origin }{ StackTrace.stackTraceAsString(failure.cause) }
}
private def timeoutToXml(timeout: Timeout): NodeSeq = {
{ timeout.origin }
}
override def networkReport: String = {
val report = for {
hubConfig <- config.hubConfig
broadcaster <- broadcasterOption
} yield {
val message = newBroadcastMessageWithRunQueryRequest
val multiplexer = broadcaster.broadcast(message)
import scala.concurrent.duration._
val responses = Await.result(multiplexer.responses, hubConfig.maxQueryWaitTime).toSeq
val failures = responses.collect { case f: Failure => f }
val timeouts = responses.collect { case t: Timeout => t }
val validResults = responses.collect { case r: Result => r }
val noProblems = failures.isEmpty && timeouts.isEmpty
XmlUtil.stripWhitespace {
{ hubConfig.shouldQuerySelf }{ nodeListAsXml }{ noProblems }{ broadcaster.destinations.size }{ validResults.size }{ failures.size }{ timeouts.size }
{
nodeListAsXml
}
{
failures.map(failureToXml)
}
{
timeouts.map(timeoutToXml)
}
}.toString
}
report.getOrElse(notAHub)
}
private def newRunQueryRequest(authn: AuthenticationInfo): RunQueryRequest = {
val queryDefinition = QueryDefinition("PDD", OccuranceLimited(1, Term(config.adapterStatusQuery)))
import scala.concurrent.duration._
RunQueryRequest(
"happyProject",
3.minutes,
authn,
BroadcastMessage.Ids.next,
None,
+ None,
Set(ResultOutputType.PATIENT_COUNT_XML),
queryDefinition)
}
private def newBroadcastMessageWithRunQueryRequest: BroadcastMessage = {
val req = newRunQueryRequest(networkAuthn)
signer.sign(BroadcastMessage(req.networkQueryId, networkAuthn, req), SigningCertStrategy.Attach)
}
override def adapterReport: String = {
val report = for {
adapterRequestHandler <- adapterOption
} yield {
val message = newBroadcastMessageWithRunQueryRequest
import scala.concurrent.duration._
val (resultAttempt: Try[Result], elapsed: Duration) = {
val start = System.currentTimeMillis
val attempt = Try(adapterRequestHandler.handleRequest(message))
val end = System.currentTimeMillis
(attempt, (end - start).milliseconds)
}
XmlUtil.stripWhitespace {
{
resultAttempt match {
case scala.util.Failure(cause) => failureToXml(Failure(NodeId("Local"), cause))
case scala.util.Success(Result(origin, elapsed, response)) => {
{ origin } { elapsed } { response.toXml }
}
}
}
}.toString
}
report.getOrElse(notAnAdapter)
}
override def auditReport: String = {
val report = for {
auditDao <- auditDaoOption
} yield {
val recentEntries = auditDao.findRecentEntries(10)
XmlUtil.stripWhitespace {
{
recentEntries map { entry =>
{ entry.id }{ entry.username }
}
}
}.toString
}
report.getOrElse(notAHub)
}
override def queryReport: String = {
val report = for {
adapterDao <- adapterDaoOption
} yield {
val recentQueries = adapterDao.findRecentQueries(10)
XmlUtil.stripWhitespace {
{
recentQueries.map { query =>
{ query.networkId }{ query.dateCreated }{ query.name }
}
}
}.toString
}
report.getOrElse(notAnAdapter)
}
override def versionReport: String = XmlUtil.stripWhitespace {
{ Versions.version }{ ontologyMetadata.ontologyVersion }{ adapterMappings.map(_.version).getOrElse("No adapter mappings present") }{ Versions.scmRevision }{ Versions.scmBranch }{ Versions.buildDate }
}.toString
override def all: String = {
s"$versionReport$keystoreReport$routingReport$hiveReport$networkReport$adapterReport$auditReport$queryReport"
}
}
diff --git a/commons/crypto/src/test/scala/net/shrine/crypto/DefaultSignerVerifierTest.scala b/commons/crypto/src/test/scala/net/shrine/crypto/DefaultSignerVerifierTest.scala
index eb9d49b4c..a6692d696 100644
--- a/commons/crypto/src/test/scala/net/shrine/crypto/DefaultSignerVerifierTest.scala
+++ b/commons/crypto/src/test/scala/net/shrine/crypto/DefaultSignerVerifierTest.scala
@@ -1,536 +1,536 @@
package net.shrine.crypto
import net.shrine.util.{Base64, ShouldMatchersForJUnit, XmlGcEnrichments}
import org.junit.Test
import net.shrine.protocol.BroadcastMessage
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.ResultOutputType
import net.shrine.protocol.query.Term
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.protocol.query.Modifiers
import net.shrine.protocol.query.Or
import net.shrine.protocol.ReadQueryResultRequest
import net.shrine.protocol.DefaultBreakdownResultOutputTypes
import net.shrine.protocol.query.Constrained
import net.shrine.protocol.query.ValueConstraint
import net.shrine.protocol.CertId
import java.math.BigInteger
import java.security.cert.X509Certificate
import java.security.cert.CertificateFactory
import scala.io.Source
import java.io.ByteArrayInputStream
/**
* @author clint
* @since Nov 27, 2013
*/
final class DefaultSignerVerifierTest extends ShouldMatchersForJUnit {
private val authn = AuthenticationInfo("some-domain", "some-username", Credential("sadkljlajdl", false))
private val certCollection = TestKeystore.certCollection
private val signerVerifier = new DefaultSignerVerifier(certCollection)
import SigningCertStrategy._
import scala.concurrent.duration._
@Test
def testIssuersMatchBetweenCertsWithIPsInDistinguishedNames: Unit = {
def readCert(fileName: String): X509Certificate = {
val factory = CertificateFactory.getInstance("X.509")
val source = Source.fromInputStream(getClass.getClassLoader.getResourceAsStream(fileName))
val encodedCertData = try { source.mkString } finally { source.close() }
val byteStream = new ByteArrayInputStream(Base64.fromBase64(encodedCertData))
try { factory.generateCertificate(byteStream).asInstanceOf[X509Certificate] }
finally { byteStream.close() }
}
val ca = readCert("test-caroot.pem")
val alpha = readCert("test-alpha-signed.pem")
val beta = readCert("test-beta-signed.pem")
val gamma = readCert("test-gamma-signed.pem")
def shouldMatch[F](field: X509Certificate => F)(a: X509Certificate, b: X509Certificate) {
field(a) should equal(field(b))
//Use options to handle null fields
Option(field(a)).map(_.hashCode) should equal(Option(field(b)).map(_.hashCode))
}
shouldMatch(_.getIssuerDN)(ca, alpha)
shouldMatch(_.getIssuerDN)(ca, beta)
shouldMatch(_.getIssuerDN)(ca, gamma)
shouldMatch(_.getIssuerX500Principal)(ca, alpha)
shouldMatch(_.getIssuerX500Principal)(ca, beta)
shouldMatch(_.getIssuerX500Principal)(ca, gamma)
shouldMatch(_.getIssuerUniqueID)(ca, alpha)
shouldMatch(_.getIssuerUniqueID)(ca, beta)
shouldMatch(_.getIssuerUniqueID)(ca, gamma)
ca.getSerialNumber should not equal(alpha.getSerialNumber)
ca.getSerialNumber should not equal(beta.getSerialNumber)
ca.getSerialNumber should not equal(gamma.getSerialNumber)
}
@Test
def testSigningAndVerificationQueryDefWithSubQueries: Unit = {
//A failing case reported by Ben C.
val queryDef = QueryDefinition.fromI2b2 {
(t) (493.90) Asthma(250.00) Diabet@15:32:58ANY0Event 1STARTDATEFIRSTLESSEvent 2STARTDATEFIRSTGREATEREQUAL365DAYEvent 1EVENTEvent 1SAMEINSTANCENUM011000SAMEINSTANCENUM16(493.90) Asthma, unspecified type, unspecified\\SHRINE\SHRINE\Diagnoses\Diseases of the respiratory system (460-519.99)\Chronic obstructive pulmonary disease and allied conditions (490-496.99)\Asthma (493)\Asthma, unspecified (493.9)\(493.90) Asthma, unspecified type, unspecified\Diagnoses\Diseases of the respiratory system (460-519.99)\Chronic obstructive pulmonary disease and allied conditions (490-496.99)\Asthma (493)\Asthma, unspecified (493.9)\(493.90) Asthma, unspecified type, unspecified\ENCLAfalse6(493.91) Asthma, unspecified type, with status asthmaticus\\SHRINE\SHRINE\Diagnoses\Diseases of the respiratory system (460-519.99)\Chronic obstructive pulmonary disease and allied conditions (490-496.99)\Asthma (493)\Asthma, unspecified (493.9)\(493.91) Asthma, unspecified type, with status asthmaticus\Diagnoses\Diseases of the respiratory system (460-519.99)\Chronic obstructive pulmonary disease and allied conditions (490-496.99)\Asthma (493)\Asthma, unspecified (493.9)\(493.91) Asthma, unspecified type, with status asthmaticus\ENCLAfalse6(493.92) Asthma, unspecified type, with (acute) exacerbation\\SHRINE\SHRINE\Diagnoses\Diseases of the respiratory system (460-519.99)\Chronic obstructive pulmonary disease and allied conditions (490-496.99)\Asthma (493)\Asthma, unspecified (493.9)\(493.92) Asthma, unspecified type, with (acute) exacerbation\Diagnoses\Diseases of the respiratory system (460-519.99)\Chronic obstructive pulmonary disease and allied conditions (490-496.99)\Asthma (493)\Asthma, unspecified (493.9)\(493.92) Asthma, unspecified type, with (acute) exacerbation\ENCLAfalseEvent 2EVENTEvent 2SAMEINSTANCENUM011000SAMEINSTANCENUM16(250.00) Diabetes mellitus without mention of complication, type II or unspecified type, not stated as uncontrolled\\SHRINE\SHRINE\Diagnoses\Endocrine, nutritional and metabolic diseases, and immunity disorders (240-279.99)\Diseases of other endocrine glands (249-259.99)\Diabetes mellitus (250)\Diabetes mellitus without mention of complication (250.0)\(250.00) Diabetes mellitus without mention of complication, type II or unspecified type, not stated as uncontrolled\Diagnoses\Endocrine, nutritional and metabolic diseases, and immunity disorders (240-279.99)\Diseases of other endocrine glands (249-259.99)\Diabetes mellitus (250)\Diabetes mellitus without mention of complication (250.0)\(250.00) Diabetes mellitus without mention of complication, type II or unspecified type, not stated as uncontrolled\ENCLAfalse6(530.81) Esophageal reflux\\SHRINE\SHRINE\Diagnoses\Diseases of the digestive system (520-579.99)\Diseases of esophagus, stomach, and duodenum (530-539.99)\Diseases of esophagus (530)\Other specified disorders of esophagus (530.8)\(530.81) Esophageal reflux\Diagnoses\Diseases of the digestive system (520-579.99)\Diseases of esophagus, stomach, and duodenum (530-539.99)\Diseases of esophagus (530)\Other specified disorders of esophagus (530.8)\(530.81) Esophageal reflux\ENCLAfalse
}.get
def shouldVerify(signingCertStrategy: SigningCertStrategy): Unit = {
val resultTypes = DefaultBreakdownResultOutputTypes.toSet + ResultOutputType.PATIENT_COUNT_XML
- val unsignedMessage = BroadcastMessage(authn, RunQueryRequest("some-project-id", 12345.milliseconds, authn, 8934765L, Some("topic-id"), resultTypes, queryDef))
+ val unsignedMessage = BroadcastMessage(authn, RunQueryRequest("some-project-id", 12345.milliseconds, authn, 8934765L, Some("topic-id"), Some("Topic Name"), resultTypes, queryDef))
val signedMessage = signerVerifier.sign(unsignedMessage, signingCertStrategy)
signerVerifier.verifySig(signedMessage, 1.hour) should be(true)
//NB: Simulate going from one machine to another
val roundTripped = xmlRoundTrip(signedMessage)
roundTripped.signature should equal(signedMessage.signature)
signerVerifier.verifySig(roundTripped, 1.hour) should be(true)
}
//shouldVerify(Attach)
shouldVerify(DontAttach)
}
//See https://open.med.harvard.edu/jira/browse/SHRINE-859
@Test
def testSigningAndVerificationQueryNameWithSpaces: Unit = {
def shouldVerify(queryName: String, signingCertStrategy: SigningCertStrategy): Unit = {
val queryDef = QueryDefinition(queryName, Term("""\\PCORNET\PCORI\DEMOGRAPHIC\Age\>= 65 years old\65\"""))
val resultTypes = DefaultBreakdownResultOutputTypes.toSet + ResultOutputType.PATIENT_COUNT_XML
- val unsignedMessage = BroadcastMessage(authn, RunQueryRequest("some-project-id", 12345.milliseconds, authn, 8934765L, Some("topic-id"), resultTypes, queryDef))
+ val unsignedMessage = BroadcastMessage(authn, RunQueryRequest("some-project-id", 12345.milliseconds, authn, 8934765L, Some("topic-id"), Some("Topic Name"), resultTypes, queryDef))
val signedMessage = signerVerifier.sign(unsignedMessage, signingCertStrategy)
signerVerifier.verifySig(signedMessage, 1.hour) should be(true)
//NB: Simulate going from one machine to another
val roundTripped = xmlRoundTrip(signedMessage)
roundTripped.signature should equal(signedMessage.signature)
signerVerifier.verifySig(roundTripped, 1.hour) should be(true)
}
shouldVerify("foo", Attach)
shouldVerify(" foo", Attach)
shouldVerify("foo ", Attach)
shouldVerify("fo o", Attach)
shouldVerify(" 65 years old@13:23:00", Attach)
shouldVerify("foo", DontAttach)
shouldVerify(" foo", DontAttach)
shouldVerify("foo ", DontAttach)
shouldVerify("fo o", DontAttach)
shouldVerify(" 65 years old@13:23:00", DontAttach)
}
@Test
def testSigningAndVerification: Unit = doTestSigningAndVerification(signerVerifier)
@Test
def testSigningAndVerificationAttachedKnownCertNotSignedByCA: Unit = {
//Messages will be signed with a key that's in our keystore, but is not signed by a CA
val descriptor = KeyStoreDescriptor(
"shrine.keystore.multiple-private-keys",
"chiptesting",
Some("private-key-2"),
Seq("carra ca"),
KeyStoreType.JKS)
val mySignerVerifier = new DefaultSignerVerifier(KeyStoreCertCollection.fromClassPathResource(descriptor))
val unsignedMessage = BroadcastMessage(authn, DeleteQueryRequest("some-project-id", 12345.milliseconds, authn, 87356L))
val signedMessage = mySignerVerifier.sign(unsignedMessage, Attach)
mySignerVerifier.verifySig(signedMessage, 1.hour) should be(false)
}
@Test
def testSigningAndVerificationAttachedUnknownCertNotSignedByCA: Unit = {
//Messages will be signed with a key that's NOT in our keystore, but is not signed by a CA
val signerDescriptor = KeyStoreDescriptor(
"shrine.keystore.multiple-private-keys",
"chiptesting",
Some("private-key-2"), //This cert is NOT in TestKeystore.certCollection
Seq("carra ca"),
KeyStoreType.JKS)
val signer: Signer = new DefaultSignerVerifier(KeyStoreCertCollection.fromClassPathResource(signerDescriptor))
val verifier: Verifier = new DefaultSignerVerifier(TestKeystore.certCollection)
val unsignedMessage = BroadcastMessage(authn, DeleteQueryRequest("some-project-id", 12345.milliseconds, authn, 87356L))
val signedMessage = signer.sign(unsignedMessage, Attach)
verifier.verifySig(signedMessage, 1.hour) should be(false)
}
private def doTestSigningAndVerification(signerVerifier: Signer with Verifier): Unit = {
def doTest(signingCertStrategy: SigningCertStrategy) {
val unsignedMessage = BroadcastMessage(authn, DeleteQueryRequest("some-project-id", 12345.milliseconds, authn, 87356L))
val signedMessage = signerVerifier.sign(unsignedMessage, signingCertStrategy)
(unsignedMessage eq signedMessage) should be(false)
unsignedMessage should not equal (signedMessage)
signedMessage.networkAuthn should equal(unsignedMessage.networkAuthn)
signedMessage.request should equal(unsignedMessage.request)
signedMessage.requestId should equal(unsignedMessage.requestId)
unsignedMessage.signature should be(None)
signedMessage.signature.isDefined should be(true)
val sig = signedMessage.signature.get
sig.timestamp should not be (null)
sig.signedBy should equal(certCollection.myCertId.get)
sig.value should not be (null)
//The signed message should verify
signerVerifier.verifySig(signedMessage, 1.hour) should be(true)
def shouldNotVerify(message: BroadcastMessage) {
signerVerifier.verifySig(xmlRoundTrip(message), 1.hour) should be(false)
}
//The unsigned one should not
shouldNotVerify(unsignedMessage)
//Expired sigs shouldn't verify
signerVerifier.verifySig(signedMessage, 0.hours) should be(false)
//modifying anything should prevent verification
shouldNotVerify {
val anotherRequest = signedMessage.request.asInstanceOf[DeleteQueryRequest].copy(queryId = 123L)
signedMessage.withRequest(anotherRequest)
}
shouldNotVerify {
signedMessage.withRequestId(99999L)
}
shouldNotVerify {
signedMessage.copy(networkAuthn = signedMessage.networkAuthn.copy(domain = "askldjlakjsd"))
}
shouldNotVerify {
signedMessage.copy(networkAuthn = signedMessage.networkAuthn.copy(username = "askldjlakjsd"))
}
shouldNotVerify {
signedMessage.copy(networkAuthn = signedMessage.networkAuthn.copy(credential = signedMessage.networkAuthn.credential.copy(isToken = true)))
}
shouldNotVerify {
signedMessage.copy(networkAuthn = signedMessage.networkAuthn.copy(credential = signedMessage.networkAuthn.credential.copy(value = "oieutorutoirutioerutoireuto")))
}
shouldNotVerify {
val timestamp = signedMessage.signature.get.timestamp
import scala.concurrent.duration._
import XmlGcEnrichments._
val newTimestamp = timestamp + 123.minutes
signedMessage.withSignature(signedMessage.signature.get.copy(timestamp = newTimestamp))
}
shouldNotVerify {
val timestamp = signedMessage.signature.get.timestamp
import scala.concurrent.duration._
import XmlGcEnrichments._
val newTimestamp = timestamp + (-99).minutes
signedMessage.withSignature(signedMessage.signature.get.copy(timestamp = newTimestamp))
}
}
doTest(Attach)
doTest(DontAttach)
}
@Test
def testSigningAndVerificationModifiedTerm: Unit = {
import scala.concurrent.duration._
def doVerificationTest(signingCertStrategy: SigningCertStrategy, queryDef: QueryDefinition): Unit = {
- val req = RunQueryRequest("some-project-id", 12345.milliseconds, authn, 8934765L, Some("topic-id"), Set(ResultOutputType.PATIENT_COUNT_XML), queryDef)
+ val req = RunQueryRequest("some-project-id", 12345.milliseconds, authn, 8934765L, Some("topic-id"), Some("Topic Name"), Set(ResultOutputType.PATIENT_COUNT_XML), queryDef)
val unsignedMessage = BroadcastMessage(authn, req)
val signedMessage = signerVerifier.sign(unsignedMessage, signingCertStrategy)
(unsignedMessage eq signedMessage) should be(false)
unsignedMessage should not equal (signedMessage)
signedMessage.networkAuthn should equal(unsignedMessage.networkAuthn)
signedMessage.request should equal(unsignedMessage.request)
signedMessage.requestId should equal(unsignedMessage.requestId)
unsignedMessage.signature should be(None)
signedMessage.signature.isDefined should be(true)
val sig = signedMessage.signature.get
sig.timestamp should not be (null)
sig.signedBy should equal(certCollection.myCertId.get)
sig.value should not be (null)
//The signed message should verify
signerVerifier.verifySig(xmlRoundTrip(signedMessage), 1.hour) should be(true)
}
val t1 = Term("t1")
val t2 = Term("t2")
val t3 = Term("t3")
doVerificationTest(Attach, QueryDefinition("foo", Term("")))
doVerificationTest(Attach, QueryDefinition("foo", Constrained(t1, Some(Modifiers("n", "ap", t2.value)), None)))
doVerificationTest(Attach, QueryDefinition("foo", Or(t1, Constrained(t2, Some(Modifiers("n", "ap", t3.value)), None))))
doVerificationTest(Attach, QueryDefinition("foo", Or(t1, Constrained(t2, None, Some(ValueConstraint("foo", Some("bar"), "baz", "Nuh"))))))
doVerificationTest(Attach, QueryDefinition("foo", Or(t1, Constrained(t2, None, Some(ValueConstraint("foo", None, "baz", "Nuh"))))))
doVerificationTest(DontAttach, QueryDefinition("foo", Term("")))
doVerificationTest(DontAttach, QueryDefinition("foo", Constrained(t1, Some(Modifiers("n", "ap", t2.value)), None)))
doVerificationTest(DontAttach, QueryDefinition("foo", Or(t1, Constrained(t2, Some(Modifiers("n", "ap", t3.value)), None))))
doVerificationTest(DontAttach, QueryDefinition("foo", Or(t1, Constrained(t2, None, Some(ValueConstraint("foo", Some("bar"), "baz", "Nuh"))))))
doVerificationTest(DontAttach, QueryDefinition("foo", Or(t1, Constrained(t2, None, Some(ValueConstraint("foo", None, "baz", "Nuh"))))))
}
@Test
def testSigningAndVerificationReadQueryResultRequest: Unit = {
def doTest(signingCertStrategy: SigningCertStrategy) {
val localAuthn = AuthenticationInfo("i2b2demo", "shrine", Credential("SessionKey:PX4LlvLrMhybWRQfoobarbaz", true))
import scala.concurrent.duration._
val unsignedMessage = BroadcastMessage(authn, ReadQueryResultRequest("SHRINE", 180.seconds, localAuthn, 7923919416951966472L))
val signedMessage = signerVerifier.sign(unsignedMessage, signingCertStrategy)
(unsignedMessage eq signedMessage) should be(false)
unsignedMessage should not equal (signedMessage)
signedMessage.networkAuthn should equal(unsignedMessage.networkAuthn)
signedMessage.request should equal(unsignedMessage.request)
signedMessage.requestId should equal(unsignedMessage.requestId)
unsignedMessage.signature should be(None)
signedMessage.signature.isDefined should be(true)
val sig = signedMessage.signature.get
sig.timestamp should not be (null)
sig.signedBy should equal(certCollection.myCertId.get)
sig.value should not be (null)
import scala.concurrent.duration._
//The signed message should verify
signerVerifier.verifySig(xmlRoundTrip(signedMessage), 1.hour) should be(true)
}
doTest(Attach)
doTest(DontAttach)
}
private def getCertByAlias(alias: String) = certCollection.asInstanceOf[KeyStoreCertCollection].getX509Cert(alias).get
@Test
def testIsSignedByTrustedCA: Unit = {
import signerVerifier.isSignedByTrustedCA
val signedByCa = getCertByAlias("test-cert")
val notSignedByCa = getCertByAlias("spin-t1")
isSignedByTrustedCA(signedByCa).get should be(true)
isSignedByTrustedCA(notSignedByCa).isFailure should be(true)
//TODO: Test case where isSignedByTrustedCA produces Success(false):
//where CA cert (param's issuer-DN) IS in our keystore, but X509Certificate.verify(PublicKey) returns false
}
@Test
def testObtainAndValidateSigningCert: Unit = {
import signerVerifier.obtainAndValidateSigningCert
import scala.concurrent.duration._
val unsignedMessage = BroadcastMessage(authn, ReadQueryResultRequest("SHRINE", 180.seconds, authn, 7923919416951966472L))
//attached signing cert signed by known CA
{
val signedMessageWithAttachedSigner = signerVerifier.sign(unsignedMessage, SigningCertStrategy.Attach)
val signerCert = obtainAndValidateSigningCert(signedMessageWithAttachedSigner.signature.get).get
signerCert should equal(getCertByAlias("test-cert"))
}
//Known signer, no attached signing cert
{
val signedMessageWithoutAttachedSigner = signerVerifier.sign(unsignedMessage, SigningCertStrategy.DontAttach)
val signerCert = obtainAndValidateSigningCert(signedMessageWithoutAttachedSigner.signature.get).get
signerCert should equal(getCertByAlias("test-cert"))
}
//No attached cert, unknown signer: obtaining signing cert should fail
{
val signedMessage = signerVerifier.sign(unsignedMessage, SigningCertStrategy.DontAttach)
val unknownSigner = CertId(new BigInteger("-1"))
val signedMessageWithUnknownSigner = signedMessage.copy(signature = Some(signedMessage.signature.get.copy(signedBy = unknownSigner)))
val signerCertAttempt = obtainAndValidateSigningCert(signedMessageWithUnknownSigner.signature.get)
signerCertAttempt.isFailure should be(true)
}
}
private def xmlRoundTrip(message: BroadcastMessage): BroadcastMessage = {
val roundTripped = BroadcastMessage.fromXml(message.toXml).get
roundTripped should equal(message)
message
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/main/scala/net/shrine/protocol/RunQueryRequest.scala b/commons/protocol/src/main/scala/net/shrine/protocol/RunQueryRequest.scala
index 7c9d71b55..905e65c2e 100644
--- a/commons/protocol/src/main/scala/net/shrine/protocol/RunQueryRequest.scala
+++ b/commons/protocol/src/main/scala/net/shrine/protocol/RunQueryRequest.scala
@@ -1,165 +1,171 @@
package net.shrine.protocol
-import net.shrine.util.{Tries, XmlUtil, NodeSeqEnrichments, OptionEnrichments, XmlDateHelper}
+import net.shrine.util.{Tries, XmlUtil, NodeSeqEnrichments, OptionEnrichments}
import net.shrine.protocol.query.QueryDefinition
import scala.xml.NodeSeq
import scala.xml.Elem
import scala.concurrent.duration.Duration
import scala.util.Try
import net.shrine.serialization.I2b2UnmarshallingHelpers
/**
* @author Bill Simons
* @since 3/9/11
* @see http://cbmi.med.harvard.edu
* @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @see http://www.gnu.org/licenses/lgpl.html
*
* NB: this is a case class to get a structural equality contract in hashCode and equals, mostly for testing
*/
final case class RunQueryRequest(
override val projectId: String,
override val waitTime: Duration,
override val authn: AuthenticationInfo,
networkQueryId: Long,
- topicId: Option[String], //data steward when required only
+ topicId: Option[String], //data steward when required only todo would be better to use a tuple Option[(TopicId,TopicName)]
+ topicName: Option[String], //data steward when required only
outputTypes: Set[ResultOutputType],
queryDefinition: QueryDefinition) extends ShrineRequest(projectId, waitTime, authn) with CrcRequest with TranslatableRequest[RunQueryRequest] with HandleableShrineRequest with HandleableI2b2Request {
override val requestType = RequestType.QueryDefinitionRequest
override def handle(handler: ShrineRequestHandler, shouldBroadcast: Boolean) = handler.runQuery(this, shouldBroadcast)
override def handleI2b2(handler: I2b2RequestHandler, shouldBroadcast: Boolean) = handler.runQuery(this, shouldBroadcast)
def elideAuthenticationInfo: RunQueryRequest = copy(authn = AuthenticationInfo.elided)
//NB: Sort ResultOutputTypes, for deterministic testing
private def sortedOutputTypes: Seq[ResultOutputType] = outputTypes.toSeq.sortBy(_.name)
override def toXml: NodeSeq = XmlUtil.stripWhitespace {
import OptionEnrichments._
{ headerFragment }
{ networkQueryId }
{ topicId.toXml() }
+ { topicName.toXml() }
{ sortedOutputTypes.map(_.toXml) }
{ queryDefinition.toXml }
}
protected override def i2b2MessageBody: NodeSeq = XmlUtil.stripWhitespace {
import OptionEnrichments._
{ i2b2PsmHeaderWithDomain }
{ queryDefinition.toI2b2 }
{
for {
(outputType, i) <- sortedOutputTypes.zipWithIndex
priorityIndex = outputType.id.getOrElse(i + 1)
} yield {
}
}
{ topicId.toXml() }
+ { topicName.toXml() }
}
override def withProject(proj: String) = this.copy(projectId = proj)
override def withAuthn(ai: AuthenticationInfo) = this.copy(authn = ai)
def withQueryDefinition(qDef: QueryDefinition) = this.copy(queryDefinition = qDef)
def mapQueryDefinition(f: QueryDefinition => QueryDefinition) = this.withQueryDefinition(f(queryDefinition))
def withNetworkQueryId(id: Long) = this.copy(networkQueryId = id)
}
object RunQueryRequest extends I2b2XmlUnmarshaller[RunQueryRequest] with ShrineXmlUnmarshaller[RunQueryRequest] with ShrineRequestUnmarshaller with I2b2UnmarshallingHelpers {
val neededI2b2Namespace = "http://www.i2b2.org/xsd/cell/crc/psm/1.1/"
override def fromI2b2(breakdownTypes: Set[ResultOutputType])(xml: NodeSeq): Try[RunQueryRequest] = {
val queryDefNode = xml \ "message_body" \ "request" \ "query_definition"
val queryDefXml = queryDefNode.head match {
//NB: elem.scope.getPrefix(neededI2b2Namespace) will return null if elem isn't part of a larger XML chunk that has
//the http://www.i2b2.org/xsd/cell/crc/psm/1.1/ declared
case elem: Elem => elem.copy(elem.scope.getPrefix(neededI2b2Namespace))
case _ => throw new Exception("When unmarshalling a RunQueryRequest, encountered unexpected XML: '" + queryDefNode + "', might be missing.")
}
val attempt = for {
projectId <- i2b2ProjectId(xml)
waitTime <- i2b2WaitTime(xml)
authn <- i2b2AuthenticationInfo(xml)
topicId = (xml \ "message_body" \ "shrine" \ "queryTopicID").headOption.map(XmlUtil.trim)
+ topicName = (xml \ "message_body" \ "shrine" \ "queryTopicName").headOption.map(XmlUtil.trim)
outputTypes = determineI2b2OutputTypes(breakdownTypes)(xml \ "message_body" \ "request" \ "result_output_list")
queryDef <- QueryDefinition.fromI2b2(queryDefXml)
} yield {
RunQueryRequest(
projectId,
waitTime,
authn,
- -1L, //TODO: appropriate?
+ -1L, //TODO: appropriate? todo really annoying for ACT metrics audit
topicId,
+ topicName,
outputTypes,
queryDef)
}
attempt.map(addPatientCountXmlIfNecessary)
}
private def determineI2b2OutputTypes(breakdownTypes: Set[ResultOutputType])(nodeSeq: NodeSeq): Set[ResultOutputType] = {
val sequence = (nodeSeq \ "result_output").flatMap { breakdownXml =>
val breakdownName = XmlUtil.trim(breakdownXml \ "@name")
ResultOutputType.valueOf(breakdownTypes)(breakdownName)
}
sequence.toSet
}
private def determineShrineOutputTypes(nodeSeq: NodeSeq): Set[ResultOutputType] = {
val attempts = (nodeSeq \ "resultType").map(ResultOutputType.fromXml)
Tries.sequence(attempts).map(_.toSet).get
}
private[protocol] def addPatientCountXmlIfNecessary(req: RunQueryRequest): RunQueryRequest = {
import ResultOutputType.PATIENT_COUNT_XML
if (req.outputTypes.contains(PATIENT_COUNT_XML)) { req }
else { req.copy(outputTypes = req.outputTypes + PATIENT_COUNT_XML) }
}
override def fromXml(breakdownTypes: Set[ResultOutputType])(xml: NodeSeq): Try[RunQueryRequest] = {
import NodeSeqEnrichments.Strictness._
val attempt = for {
projectId <- shrineProjectId(xml)
waitTime <- shrineWaitTime(xml)
authn <- shrineAuthenticationInfo(xml)
queryId <- xml.withChild("queryId").map(XmlUtil.toLong)
topicId = (xml \ "topicId").headOption.map(XmlUtil.trim)
+ topicName = (xml \ "topicName").headOption.map(XmlUtil.trim)
outputTypes <- xml.withChild("outputTypes").map(determineShrineOutputTypes)
queryDef <- xml.withChild(QueryDefinition.rootTagName).flatMap(QueryDefinition.fromXml)
} yield {
- RunQueryRequest(projectId, waitTime, authn, queryId, topicId, outputTypes, queryDef)
+ RunQueryRequest(projectId, waitTime, authn, queryId, topicId, topicName, outputTypes, queryDef)
}
attempt.map(addPatientCountXmlIfNecessary)
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/test/scala/net/shrine/protocol/HandleableI2b2RequestTest.scala b/commons/protocol/src/test/scala/net/shrine/protocol/HandleableI2b2RequestTest.scala
index dd16750d2..a6edc1b49 100644
--- a/commons/protocol/src/test/scala/net/shrine/protocol/HandleableI2b2RequestTest.scala
+++ b/commons/protocol/src/test/scala/net/shrine/protocol/HandleableI2b2RequestTest.scala
@@ -1,87 +1,87 @@
package net.shrine.protocol
import net.shrine.util.ShouldMatchersForJUnit
import org.junit.Test
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
/**
* @author clint
- * @date Jun 18, 2014
+ * @since Jun 18, 2014
*/
final class HandleableI2b2RequestTest extends ShouldMatchersForJUnit {
type Req = ShrineRequest with HandleableI2b2Request
import HandleableI2b2Request.fromI2b2
import scala.concurrent.duration._
private val authn = AuthenticationInfo("some-domain", "some-user", Credential("some-password", false))
private val waitTime = 1.minute
private val projectId = "some-project-id"
@Test
def testFromI2b2ReadResultOutputTypesRequest: Unit = {
val i2b2Xml = ReadResultOutputTypesRequestTest.i2b2Xml(CrcRequestType.GetResultOutputTypes)
val req = fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(i2b2Xml).get
req.authn should equal(ReadResultOutputTypesRequestTest.authn)
req.projectId should equal(ReadResultOutputTypesRequestTest.projectId)
req.waitTime should equal(ReadResultOutputTypesRequestTest.waitTime)
}
@Test
def testFromI2b2: Unit = {
def roundTrip(req: Req): Unit = {
val xml = req.toI2b2
val unmarshalled = fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(xml).get
(req, unmarshalled) match {
//NB: Special handling for RunQueryRequest, which does not preserve networkQueryIds when serializing to i2b2 format
case (expected: RunQueryRequest, actual: RunQueryRequest) => {
//NB: When unmarshalling from i2b2 format, networkQueryId will always be -1; other fields should be fine
actual should equal(expected.withNetworkQueryId(-1L))
}
case _ => unmarshalled should equal(req)
}
}
//Junk input
fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(null).isFailure should be(true)
fromI2b2(DefaultBreakdownResultOutputTypes.toSet)().isFailure should be(true)
val queryDef = QueryDefinition("foo", Term("foo"))
//A request that isn't a HandleableI2b2Request
val invalidReq = ReadTranslatedQueryDefinitionRequest(authn, waitTime, queryDef)
fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(invalidReq.toXml).isFailure should be(true)
val networkQueryId = 12345L
val userId = "some-user"
fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(ReadPdoRequest(projectId, waitTime, authn, "patient-set-coll-id", ).toI2b2).isFailure should be(true)
roundTrip(DeleteQueryRequest(projectId, waitTime, authn, networkQueryId))
roundTrip(FlagQueryRequest(projectId, waitTime, authn, networkQueryId, None))
roundTrip(FlagQueryRequest(projectId, waitTime, authn, networkQueryId, Some("some-message")))
roundTrip(UnFlagQueryRequest(projectId, waitTime, authn, networkQueryId))
roundTrip(UnFlagQueryRequest(projectId, waitTime, authn, networkQueryId))
roundTrip(ReadApprovedQueryTopicsRequest(projectId, waitTime, authn, userId))
roundTrip(ReadInstanceResultsRequest(projectId, waitTime, authn, networkQueryId))
//Make minimal PDO request (kind of finnicky due to embedded XML)
val patientSetCollId = "patient-set-coll-id"
val optionsXml = { CrcRequestType.GetPDOFromInputListRequestType.i2b2RequestType }{ patientSetCollId }
val pdoXml = ReadPdoRequest.updateCollId(optionsXml.head, patientSetCollId).toSeq
roundTrip(ReadPdoRequest(projectId, waitTime, authn, patientSetCollId, pdoXml))
roundTrip(ReadPreviousQueriesRequest(projectId, waitTime, authn, userId, 123))
roundTrip(ReadQueryDefinitionRequest(projectId, waitTime, authn, networkQueryId))
roundTrip(ReadQueryInstancesRequest(projectId, waitTime, authn, networkQueryId))
roundTrip(RenameQueryRequest(projectId, waitTime, authn, networkQueryId, "new-name"))
- roundTrip(RunQueryRequest(projectId, waitTime /*.toMillis.milliseconds*/ , authn, networkQueryId, Some("some-topic-id"), Set(ResultOutputType.PATIENT_COUNT_XML), queryDef))
- roundTrip(RunQueryRequest(projectId, waitTime /*.toMillis.milliseconds*/ , authn, networkQueryId, None, Set(ResultOutputType.PATIENT_COUNT_XML), queryDef))
+ roundTrip(RunQueryRequest(projectId, waitTime /*.toMillis.milliseconds*/ , authn, networkQueryId, Some("some-topic-id"),Some("some-topic-name"), Set(ResultOutputType.PATIENT_COUNT_XML), queryDef))
+ roundTrip(RunQueryRequest(projectId, waitTime /*.toMillis.milliseconds*/ , authn, networkQueryId, None, None, Set(ResultOutputType.PATIENT_COUNT_XML), queryDef))
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/test/scala/net/shrine/protocol/HiveCredentialsTest.scala b/commons/protocol/src/test/scala/net/shrine/protocol/HiveCredentialsTest.scala
index 7a90bfece..86151f06a 100644
--- a/commons/protocol/src/test/scala/net/shrine/protocol/HiveCredentialsTest.scala
+++ b/commons/protocol/src/test/scala/net/shrine/protocol/HiveCredentialsTest.scala
@@ -1,23 +1,22 @@
package net.shrine.protocol
-import net.shrine.protocol.HiveCredentials
import net.shrine.util.ShouldMatchersForJUnit
/**
* @author clint
* @since Oct 4, 2012
*/
final class HiveCredentialsTest extends ShouldMatchersForJUnit {
- def testToAuthenticationInfo {
+ def testToAuthenticationInfo() {
val creds = HiveCredentials("domain", "username", "password", "project")
val authn = creds.toAuthenticationInfo
- authn should not be(null)
+ authn should not be null
authn.domain should equal(creds.domain)
authn.username should equal(creds.username)
authn.credential.value should equal(creds.password)
- authn.credential.isToken should be(false)
+ authn.credential.isToken should be(right = false)
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/test/scala/net/shrine/protocol/RunQueryRequestTest.scala b/commons/protocol/src/test/scala/net/shrine/protocol/RunQueryRequestTest.scala
index 57fb67f03..13273eb90 100644
--- a/commons/protocol/src/test/scala/net/shrine/protocol/RunQueryRequestTest.scala
+++ b/commons/protocol/src/test/scala/net/shrine/protocol/RunQueryRequestTest.scala
@@ -1,468 +1,476 @@
package net.shrine.protocol
import org.junit.Test
import xml.Utility
import scala.xml.XML
import net.shrine.util.XmlUtil
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.OccuranceLimited
import net.shrine.protocol.query.Term
/**
* @author Bill Simons
- * @date 3/17/11
- * @link http://cbmi.med.harvard.edu
- * @link http://chip.org
+ * @since 3/17/11
+ * @see http://cbmi.med.harvard.edu
+ * @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
- * @link http://www.gnu.org/licenses/lgpl.html
+ * @see http://www.gnu.org/licenses/lgpl.html
*/
final class RunQueryRequestTest extends ShrineRequestValidator {
private val queryId = 98765L
private val topicId = "1"
+ private val topicName = "Test Topic"
private val queryDefinition = QueryDefinition("Ostium secundum@14:01:35", Term("""\\SHRINE\SHRINE\Diagnoses\Congenital anomalies\Cardiac and circulatory congenital anomalies\Atrial septal defect\Ostium secundum type atrial septal defect\"""))
private val resultOutputTypes = {
import ResultOutputType._
(Seq(PATIENTSET, PATIENT_COUNT_XML) ++ DefaultBreakdownResultOutputTypes.values).sortBy(_.name).zipWithIndex.map {
case (rot, i) =>
rot.withId(i + 1)
}
}
private val nonCountResultOutputTypes = resultOutputTypes.filterNot(_ == ResultOutputType.PATIENT_COUNT_XML)
//add weird casing to make sure the code isn't case senstive, the client will send all sorts of weirdness
private val resultOutputTypesI2b2Xml = XmlUtil.stripWhitespace {
}
override def messageBody = XmlUtil.stripWhitespace {
{ username }00CRC_QRY_runQueryInstance_fromQueryDefinition
{ queryDefinition.toI2b2 }
{ resultOutputTypesI2b2Xml }
{ topicId }
}
private def messageBodyNoTopicId = XmlUtil.stripWhitespace {
{ username }00CRC_QRY_runQueryInstance_fromQueryDefinition
{ queryDefinition.toI2b2 }
{ resultOutputTypesI2b2Xml }
}
private def messageBodyNoOutputTypes = XmlUtil.stripWhitespace {
{ username }00CRC_QRY_runQueryInstance_fromQueryDefinition
{ queryDefinition.toI2b2 }
{ topicId }
}
private def messageBodyNoCountOutputType = XmlUtil.stripWhitespace {
{ username }00CRC_QRY_runQueryInstance_fromQueryDefinition
{ queryDefinition.toI2b2 }
{ topicId }
}
private val runQueryRequest = XmlUtil.stripWhitespace {
{ requestHeaderFragment }
{ queryId }{ topicId }
+ { topicName }
{ resultOutputTypes.map(_.toXml) }
{ queryDefinition.toXml }
}
private val runQueryRequestNoCountOutputType = XmlUtil.stripWhitespace {
{ requestHeaderFragment }
{ queryId }{ topicId }
{ nonCountResultOutputTypes.map(_.toXml) }
{ queryDefinition.toXml }
}
private val runQueryRequestNoOutputTypes = XmlUtil.stripWhitespace {
{ requestHeaderFragment }
{ queryId }{ topicId }
{ queryDefinition.toXml }
}
private val runQueryRequestNoTopicId = XmlUtil.stripWhitespace {
{ requestHeaderFragment }
{ queryId }
{ resultOutputTypes.map(_.toXml) }
{ queryDefinition.toXml }
}
@Test
def testAddPatientCountXmlIfNecessary: Unit = {
import scala.concurrent.duration._
import ResultOutputType._
import RunQueryRequest.addPatientCountXmlIfNecessary
val breakdownOutputType = ResultOutputType("PATIENT_GENDER_COUNT_XML", true, I2b2Options("Number of patients by gender"), Some(99))
val countReq = RunQueryRequest(
"project-Id",
1.minute,
AuthenticationInfo("d", "u", Credential("p", false)),
12345L,
None,
+ None,
Set(PATIENT_COUNT_XML, breakdownOutputType),
QueryDefinition("foo", Some(Term("bar"))))
val nonCountReq = countReq.copy(outputTypes = countReq.outputTypes - PATIENT_COUNT_XML)
val noOutputTypesReq = countReq.copy(outputTypes = Set.empty)
countReq.outputTypes.contains(PATIENT_COUNT_XML) should be(true)
nonCountReq.outputTypes.contains(PATIENT_COUNT_XML) should be(false)
addPatientCountXmlIfNecessary(countReq) should equal(countReq)
addPatientCountXmlIfNecessary(nonCountReq) should equal(countReq)
addPatientCountXmlIfNecessary(noOutputTypesReq).outputTypes should equal(Set(PATIENT_COUNT_XML))
}
@Test
def testElideAuthenticationInfo: Unit = {
val req = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request()).get
req.authn.username should equal(username)
req.authn.domain should equal(domain)
req.authn.credential.value should equal(passwd)
val elided = req.elideAuthenticationInfo
elided.authn.username should equal("*******")
elided.authn.domain should equal("*******")
elided.authn.credential.value should equal("*******")
}
@Test
override def testFromI2b2 {
val translatedRequest = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request()).get
validateRequestWith(translatedRequest) {
translatedRequest.topicId should equal(Some(topicId))
translatedRequest.outputTypes should equal(ResultOutputType.nonErrorTypes.toSet ++ DefaultBreakdownResultOutputTypes.toSet)
translatedRequest.queryDefinition should equal(queryDefinition)
val queryDefNode = translatedRequest.queryDefinition.toI2b2
queryDefNode.head.prefix should equal(queryDefNode.head.scope.getPrefix(RunQueryRequest.neededI2b2Namespace))
}
}
@Test
def testFromI2b2NoTopicId {
val translatedRequest = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request(() => messageBodyNoTopicId)).get
validateRequestWith(translatedRequest) {
translatedRequest.topicId should equal(None)
translatedRequest.outputTypes should equal(ResultOutputType.nonErrorTypes.toSet ++ DefaultBreakdownResultOutputTypes.toSet)
translatedRequest.queryDefinition should equal(queryDefinition)
val queryDefNode = translatedRequest.queryDefinition.toI2b2
queryDefNode.head.prefix should equal(queryDefNode.head.scope.getPrefix(RunQueryRequest.neededI2b2Namespace))
}
}
@Test
def testFromI2b2NoOutputTypes {
val translatedRequest = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request(() => messageBodyNoOutputTypes)).get
validateRequestWith(translatedRequest) {
translatedRequest.topicId should equal(Some(topicId))
translatedRequest.outputTypes should equal(Set(ResultOutputType.PATIENT_COUNT_XML))
translatedRequest.queryDefinition should equal(queryDefinition)
val queryDefNode = translatedRequest.queryDefinition.toI2b2
queryDefNode.head.prefix should equal(queryDefNode.head.scope.getPrefix(RunQueryRequest.neededI2b2Namespace))
}
}
@Test
def testFromI2b2NoCountOutputType {
val translatedRequest = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request(() => messageBodyNoCountOutputType)).get
validateRequestWith(translatedRequest) {
translatedRequest.topicId should equal(Some(topicId))
translatedRequest.outputTypes should equal(DefaultBreakdownResultOutputTypes.toSet + ResultOutputType.PATIENT_COUNT_XML)
translatedRequest.queryDefinition should equal(queryDefinition)
val queryDefNode = translatedRequest.queryDefinition.toI2b2
queryDefNode.head.prefix should equal(queryDefNode.head.scope.getPrefix(RunQueryRequest.neededI2b2Namespace))
}
}
@Test
def testMapQueryDefinition {
val outputTypes = ResultOutputType.nonBreakdownTypes.toSet
- val req = new RunQueryRequest(projectId, waitTime, authn, queryId, Option(topicId), outputTypes, queryDefinition)
+ val req = new RunQueryRequest(projectId, waitTime, authn, queryId, Option(topicId), Option(topicName), outputTypes, queryDefinition)
val bogusTerm = Term("sa;ldk;alskd")
val mapped = req.mapQueryDefinition(_.transform(_ => bogusTerm))
(mapped eq req) should not be (true)
mapped should not equal (req)
mapped.projectId should equal(projectId)
mapped.waitTime should equal(waitTime)
mapped.authn should equal(authn)
mapped.topicId should equal(Option(topicId))
mapped.outputTypes should equal(outputTypes)
mapped.queryDefinition.name should equal(queryDefinition.name)
mapped.queryDefinition.expr.get should equal(bogusTerm)
}
@Test
override def testShrineRequestFromI2b2 {
val shrineRequest = CrcRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request()).get
shrineRequest.isInstanceOf[RunQueryRequest] should be(true)
}
@Test
def testDoubleDispatchingShrineRequestFromI2b2 {
val shrineRequest = HandleableShrineRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(request()).get
shrineRequest.isInstanceOf[RunQueryRequest] should be(true)
}
@Test
def testShrineXmlRoundTrip: Unit = {
def doTest(outputTypes: Set[ResultOutputType]) {
val req = RunQueryRequest(
projectId,
waitTime,
authn,
queryId,
Option(topicId),
+ Option(topicName),
outputTypes,
queryDefinition)
val roundTripped = RunQueryRequest.fromXml(Set.empty)(req.toXml).get
roundTripped should equal(req)
}
doTest(ResultOutputType.nonErrorTypes.toSet)
doTest(ResultOutputType.nonErrorTypes.toSet ++ DefaultBreakdownResultOutputTypes.toSet)
}
@Test
override def testToXml {
import scala.concurrent.duration._
RunQueryRequest(
projectId,
waitTime,
authn,
queryId,
Option(topicId),
+ Option(topicName),
resultOutputTypes.toSet,
queryDefinition).toXml should equal(runQueryRequest)
}
@Test
def testToXmlNoTopicId {
RunQueryRequest(
projectId,
waitTime,
authn,
queryId,
None,
+ None,
resultOutputTypes.toSet,
queryDefinition).toXml should equal(runQueryRequestNoTopicId)
}
@Test
override def testToI2b2 {
val req = RunQueryRequest(
projectId,
waitTime,
authn,
queryId,
Option(topicId),
+ Option(topicName),
resultOutputTypes.toSet,
queryDefinition)
val actual = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(req.toI2b2).get
validateRequestWith(actual) {
actual.networkQueryId should equal(-1L)
actual.topicId should equal(Some(topicId))
actual.outputTypes should equal(resultOutputTypes.toSet)
actual.queryDefinition should equal(queryDefinition)
}
}
@Test
def testToI2b2NoTopicId {
val req = RunQueryRequest(
projectId,
waitTime,
authn,
queryId,
None,
+ None,
resultOutputTypes.toSet,
queryDefinition)
val actual = RunQueryRequest.fromI2b2(DefaultBreakdownResultOutputTypes.toSet)(req.toI2b2).get
validateRequestWith(actual) {
actual.networkQueryId should equal(-1L)
actual.topicId should equal(None)
actual.outputTypes should equal(resultOutputTypes.toSet)
actual.queryDefinition should equal(queryDefinition)
}
}
@Test
override def testFromXml {
val actual = RunQueryRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(runQueryRequest).get
validateRequestWith(actual) {
actual.networkQueryId should equal(queryId)
actual.topicId should equal(Some(topicId))
actual.outputTypes should equal(resultOutputTypes.toSet)
actual.queryDefinition should equal(queryDefinition)
val queryDefNode = actual.queryDefinition.toXml.head
queryDefNode.prefix should be(null)
queryDefNode.namespace should be(null)
}
}
@Test
def testFromXmlNoTopicId {
val actual = RunQueryRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(runQueryRequestNoTopicId).get
validateRequestWith(actual) {
actual.networkQueryId should equal(queryId)
actual.topicId should equal(None)
actual.outputTypes should equal(resultOutputTypes.toSet)
actual.queryDefinition should equal(queryDefinition)
val queryDefNode = actual.queryDefinition.toXml.head
queryDefNode.prefix should be(null)
queryDefNode.namespace should be(null)
}
}
@Test
def testFromXmlNoOutputTypes {
val actual = RunQueryRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(runQueryRequestNoOutputTypes).get
validateRequestWith(actual) {
actual.networkQueryId should equal(queryId)
actual.topicId should equal(Some(topicId))
actual.outputTypes should equal(Set(ResultOutputType.PATIENT_COUNT_XML))
actual.queryDefinition should equal(queryDefinition)
val queryDefNode = actual.queryDefinition.toXml.head
queryDefNode.prefix should be(null)
queryDefNode.namespace should be(null)
}
}
@Test
def testFromXmlNoCountOutputType {
val actual = RunQueryRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(runQueryRequestNoCountOutputType).get
validateRequestWith(actual) {
actual.networkQueryId should equal(queryId)
actual.topicId should equal(Some(topicId))
actual.outputTypes should equal(nonCountResultOutputTypes.toSet + ResultOutputType.PATIENT_COUNT_XML)
actual.queryDefinition should equal(queryDefinition)
val queryDefNode = actual.queryDefinition.toXml.head
queryDefNode.prefix should be(null)
queryDefNode.namespace should be(null)
}
}
@Test
def testShrineRequestFromXml {
ShrineRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(runQueryRequest).get.isInstanceOf[RunQueryRequest] should be(true)
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/test/scala/net/shrine/protocol/ShrineMessageTest.scala b/commons/protocol/src/test/scala/net/shrine/protocol/ShrineMessageTest.scala
index 50b4386d0..971c9ea17 100644
--- a/commons/protocol/src/test/scala/net/shrine/protocol/ShrineMessageTest.scala
+++ b/commons/protocol/src/test/scala/net/shrine/protocol/ShrineMessageTest.scala
@@ -1,174 +1,175 @@
package net.shrine.protocol
import net.shrine.serialization.XmlMarshaller
import net.shrine.serialization.XmlUnmarshaller
import net.shrine.util.ShouldMatchersForJUnit
import org.junit.Test
import scala.util.Try
import scala.xml.NodeSeq
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.util.XmlDateHelper
import java.math.BigInteger
/**
* @author clint
- * @date Feb 24, 2014
+ * @since Feb 24, 2014
*/
final class ShrineMessageTest extends ShouldMatchersForJUnit {
@Test
def testRoundTrips {
val projectId = "salkdjksaljdkla"
import scala.concurrent.duration._
val waitTime: Duration = 98374L.milliseconds
val userId = "foo-user"
val groupId = "foo-group"
val authn = AuthenticationInfo("blarg-domain", userId, Credential("sajkhdkjsadh", true))
val queryId = 485794359L
val patientSetCollId = "ksaldjksal"
val optionsXml: NodeSeq = x
val fetchSize = 12345
val queryName = "saljkd;salda"
val topicId = "saldjkasljdasdsadsadasdas"
+ val topicName = "Topic Name"
val outputTypes = ResultOutputType.nonBreakdownTypes.toSet
val queryDefinition = QueryDefinition(queryName, Term("oiweruoiewkldfhsofi"))
val queryDefinition2 = QueryDefinition(queryName, Term("a;slkjflfjlsdkjf"))
val localResultId = "aoiduaojsdpaojcmsal"
val nodeId = NodeId("foo")
val nodeId2 = NodeId("bar")
val queryTopicId1 = 123L
val queryTopicId2 = 456L
val queryTopicName1 = "nuh"
val queryTopicName2 = "zuh"
val shrineNetworkQueryId = 1287698235L
val start = Some(XmlDateHelper.now)
val end = Some(XmlDateHelper.now)
val singleNodeResult1 = QueryResult.errorResult(Some("blarg"), "glarg")
val singleNodeResult2 = QueryResult(
42L,
99L,
Option(ResultOutputType.PATIENT_COUNT_XML),
123L,
start,
end,
Some("description"),
QueryResult.StatusType.Finished,
Some("status"))
val param1 = ParamResponse("foo", "bar", "baz")
val queryMaster1 = QueryMaster("kjasdh", 12345L, "name1", userId, groupId, start.get)
val queryMaster2 = QueryMaster("skdjlhlasf", 873563L, "name2", userId, groupId, end.get)
val queryInstance1 = QueryInstance("asd", "42", userId, groupId, start.get, end.get)
val queryInstance2 = QueryInstance("asdasd", "99", userId, groupId, start.get, end.get)
val envelope = I2b2ResultEnvelope(DefaultBreakdownResultOutputTypes.PATIENT_AGE_COUNT_XML, Map("x" -> 1, "y" -> 2))
//BroadcastMessage
//Non-CA-signed signing cert
doMarshallingRoundTrip(BroadcastMessage(123456L, authn, DeleteQueryRequest(projectId, waitTime, authn, queryId), Some(Signature(XmlDateHelper.now, CertId(new BigInteger("1234567890")), None, "asdf".getBytes))))
//CA-signed signing cert
doMarshallingRoundTrip(BroadcastMessage(123456L, authn, DeleteQueryRequest(projectId, waitTime, authn, queryId), Some(Signature(XmlDateHelper.now, CertId(new BigInteger("1234567890")), Some(CertData("cert signed by ca".getBytes)), "asdf".getBytes))))
//Non-i2b2able requests
doMarshallingRoundTrip(ReadTranslatedQueryDefinitionRequest(authn, waitTime, queryDefinition))
doMarshallingRoundTrip(ReadQueryResultRequest(projectId, waitTime, authn, queryId))
//I2b2able requests
doMarshallingRoundTrip(DeleteQueryRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(ReadApprovedQueryTopicsRequest(projectId, waitTime, authn, userId))
doMarshallingRoundTrip(ReadInstanceResultsRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(ReadPdoRequest(projectId, waitTime, authn, patientSetCollId, optionsXml))
doMarshallingRoundTrip(ReadPreviousQueriesRequest(projectId, waitTime, authn, userId, fetchSize))
doMarshallingRoundTrip(ReadQueryDefinitionRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(ReadQueryInstancesRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(RenameQueryRequest(projectId, waitTime, authn, queryId, queryName))
- doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, Option(topicId), outputTypes, queryDefinition))
- doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, None, outputTypes, queryDefinition))
+ doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, Option(topicId), Option(topicName), outputTypes, queryDefinition))
+ doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, None, None, outputTypes, queryDefinition))
doMarshallingRoundTrip(ReadResultRequest(projectId, waitTime, authn, localResultId))
//Non-i2b2able responses
doMarshallingRoundTrip(SingleNodeReadTranslatedQueryDefinitionResponse(SingleNodeTranslationResult(nodeId, queryDefinition)))
doMarshallingRoundTrip(AggregatedReadTranslatedQueryDefinitionResponse(Seq(SingleNodeTranslationResult(nodeId, queryDefinition), SingleNodeTranslationResult(nodeId2, queryDefinition2))))
//I2b2able responses
doMarshallingRoundTrip(DeleteQueryResponse(queryId))
doMarshallingRoundTrip(ReadApprovedQueryTopicsResponse(Seq(ApprovedTopic(queryTopicId1, queryTopicName1), ApprovedTopic(queryTopicId2, queryTopicName2))))
doMarshallingRoundTrip(ReadInstanceResultsResponse(shrineNetworkQueryId, singleNodeResult2))
doMarshallingRoundTrip(AggregatedReadInstanceResultsResponse(shrineNetworkQueryId, Seq(singleNodeResult1, singleNodeResult2)))
doMarshallingRoundTrip(ReadPdoResponse(Seq(EventResponse("foo", "bar", start, end, Seq(param1))), Seq(PatientResponse("nuh", Seq(param1))), Nil))
doMarshallingRoundTrip(ReadPreviousQueriesResponse(Seq(queryMaster1, queryMaster2)))
doMarshallingRoundTrip(ReadQueryDefinitionResponse(42L, "name", userId, start.get, queryDefinition.toXmlString))
doMarshallingRoundTrip(ReadQueryInstancesResponse(42L, userId, groupId, Seq(queryInstance1, queryInstance2)))
doMarshallingRoundTrip(RenameQueryResponse(12345L, queryName))
doMarshallingRoundTrip(RunQueryResponse(queryId, start.get, userId, groupId, queryDefinition, 12345L, singleNodeResult1))
doMarshallingRoundTrip(AggregatedRunQueryResponse(queryId, start.get, userId, groupId, queryDefinition, 12345L, Seq(singleNodeResult1, singleNodeResult2)))
doMarshallingRoundTrip(ReadResultResponse(42L, singleNodeResult2, envelope))
}
private def doMarshallingRoundTrip[T <: ShrineMessage](message: T) {
val xml = message.toXml
val unmarshalled = ShrineMessage.fromXml(DefaultBreakdownResultOutputTypes.toSet)(xml).get
message match {
//NB: Special handling of ReadPdoRequest due to fiddly serialization and equality issues with its
//NodeSeq field. :( :(
case readPdoRequest: ReadPdoRequest => {
val unmarshalledReadPdoRequest = unmarshalled.asInstanceOf[ReadPdoRequest]
readPdoRequest.projectId should equal(unmarshalledReadPdoRequest.projectId)
readPdoRequest.waitTime should equal(unmarshalledReadPdoRequest.waitTime)
readPdoRequest.authn should equal(unmarshalledReadPdoRequest.authn)
readPdoRequest.patientSetCollId should equal(unmarshalledReadPdoRequest.patientSetCollId)
//NB: Ugh :(
readPdoRequest.optionsXml.toString should equal(unmarshalledReadPdoRequest.optionsXml.toString)
}
//NB: Special handling of ReadInstanceResultsResponse because its member QueryRequests are munged
//before serialization
case readInstanceResultsResponse: ReadInstanceResultsResponse => {
val unmarshalledResp = unmarshalled.asInstanceOf[ReadInstanceResultsResponse]
val expected = readInstanceResultsResponse.withQueryResult(readInstanceResultsResponse.singleNodeResult.copy(instanceId = readInstanceResultsResponse.shrineNetworkQueryId))
unmarshalledResp should equal(expected)
}
//NB: Special handling of AggregatedReadInstanceResultsResponse because its member QueryRequests are munged
//before serialization
case aggReadInstanceResultsResponse: AggregatedReadInstanceResultsResponse => {
val unmarshalledResp = unmarshalled.asInstanceOf[AggregatedReadInstanceResultsResponse]
val expected = aggReadInstanceResultsResponse.withResults(aggReadInstanceResultsResponse.results.map(_.copy(instanceId = aggReadInstanceResultsResponse.shrineNetworkQueryId)))
unmarshalledResp should equal(expected)
}
//NB: Special handling of ReadQueryInstancesResponse because its member QueryInstances are not exactly preserved
//on serialization round trips
case readQueryInstancesResponse: ReadQueryInstancesResponse => {
val unmarshalledResp = unmarshalled.asInstanceOf[ReadQueryInstancesResponse]
val expected = unmarshalledResp.withInstances(unmarshalledResp.queryInstances.map(_.copy(queryMasterId = unmarshalledResp.queryMasterId.toString)))
}
//NB: Special handling of RunQueryResponse because its member QueryRequest is munged
//during serialization
case runQueryResponse: RunQueryResponse => {
val unmarshalledResp = unmarshalled.asInstanceOf[RunQueryResponse]
val expected = runQueryResponse.withResult(runQueryResponse.singleNodeResult.copy(instanceId = runQueryResponse.queryInstanceId))
unmarshalledResp should equal(expected)
}
//NB: Special handling of AggregatedRunQueryResponse because its member QueryRequests are munged
//during serialization
case aggRunQueryResponse: AggregatedRunQueryResponse => {
val unmarshalledResp = unmarshalled.asInstanceOf[AggregatedRunQueryResponse]
val expected = aggRunQueryResponse.withResults(aggRunQueryResponse.results.map(_.copy(instanceId = aggRunQueryResponse.queryInstanceId)))
unmarshalledResp should equal(expected)
}
case _ => unmarshalled should equal(message)
}
}
}
\ No newline at end of file
diff --git a/commons/protocol/src/test/scala/net/shrine/protocol/ShrineRequestTest.scala b/commons/protocol/src/test/scala/net/shrine/protocol/ShrineRequestTest.scala
index 95bec0ef5..5d0de6ed1 100644
--- a/commons/protocol/src/test/scala/net/shrine/protocol/ShrineRequestTest.scala
+++ b/commons/protocol/src/test/scala/net/shrine/protocol/ShrineRequestTest.scala
@@ -1,78 +1,79 @@
package net.shrine.protocol
import scala.xml.NodeSeq
import org.junit.Test
import net.shrine.util.ShouldMatchersForJUnit
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import scala.xml.XML
/**
* @author clint
- * @date Mar 22, 2013
+ * @since Mar 22, 2013
*/
final class ShrineRequestTest extends ShouldMatchersForJUnit {
@Test
def testFromXmlThrowsOnBadInput {
intercept[Exception] {
ShrineRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(XML.loadString("asdasdasddas"))
}
}
@Test
def testFromXml {
val projectId = "salkdjksaljdkla"
import scala.concurrent.duration._
val waitTime: Duration = 98374L.milliseconds
val userId = "foo-user"
val authn = AuthenticationInfo("blarg-domain", userId, Credential("sajkhdkjsadh", true))
val queryId = 485794359L
val patientSetCollId = "ksaldjksal"
val optionsXml: NodeSeq = x
val fetchSize = 12345
val queryName = "saljkd;salda"
val topicId = "saldjkasljdasdsadsadasdas"
+ val topicName = "Topic Name"
val outputTypes = ResultOutputType.nonBreakdownTypes.toSet
val queryDefinition = QueryDefinition(queryName, Term("oiweruoiewkldfhsofi"))
val localResultId = "aoiduaojsdpaojcmsal"
def doMarshallingRoundTrip(req: ShrineRequest) {
val xml = req.toXml
val unmarshalled = ShrineRequest.fromXml(DefaultBreakdownResultOutputTypes.toSet)(xml)
req match {
//NB: Special handling of ReadPdoRequest due to fiddly serialization and equality issues with its NodeSeq field. :( :(
case readPdoRequest: ReadPdoRequest => {
val unmarshalledReadPdoRequest = unmarshalled.get.asInstanceOf[ReadPdoRequest]
readPdoRequest.projectId should equal(unmarshalledReadPdoRequest.projectId)
readPdoRequest.waitTime should equal(unmarshalledReadPdoRequest.waitTime)
readPdoRequest.authn should equal(unmarshalledReadPdoRequest.authn)
readPdoRequest.patientSetCollId should equal(unmarshalledReadPdoRequest.patientSetCollId)
//NB: Ugh :(
readPdoRequest.optionsXml.toString should equal(unmarshalledReadPdoRequest.optionsXml.toString)
}
case _ => unmarshalled.get should equal(req)
}
}
//doMarshallingRoundTrip(ReadQueryResultRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(DeleteQueryRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(ReadApprovedQueryTopicsRequest(projectId, waitTime, authn, userId))
doMarshallingRoundTrip(ReadInstanceResultsRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(ReadPdoRequest(projectId, waitTime, authn, patientSetCollId, optionsXml))
doMarshallingRoundTrip(ReadPreviousQueriesRequest(projectId, waitTime, authn, userId, fetchSize))
doMarshallingRoundTrip(ReadQueryDefinitionRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(ReadQueryInstancesRequest(projectId, waitTime, authn, queryId))
doMarshallingRoundTrip(RenameQueryRequest(projectId, waitTime, authn, queryId, queryName))
- doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, Option(topicId), outputTypes, queryDefinition))
- doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, None, outputTypes, queryDefinition))
+ doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, Option(topicId), Option(topicName), outputTypes, queryDefinition))
+ doMarshallingRoundTrip(RunQueryRequest(projectId, waitTime, authn, queryId, None, None, outputTypes, queryDefinition))
doMarshallingRoundTrip(ReadResultRequest(projectId, waitTime, authn, localResultId))
doMarshallingRoundTrip(FlagQueryRequest(projectId, waitTime, authn, queryId, None))
doMarshallingRoundTrip(FlagQueryRequest(projectId, waitTime, authn, queryId, Some("some-message")))
doMarshallingRoundTrip(UnFlagQueryRequest(projectId, waitTime, authn, queryId))
}
}
\ No newline at end of file
diff --git a/hms-support/hms-core/src/test/scala/net/shrine/hms/authorization/HmsDataStewardAuthorizationServiceTest.scala b/hms-support/hms-core/src/test/scala/net/shrine/hms/authorization/HmsDataStewardAuthorizationServiceTest.scala
index ca52d56dd..bbde17919 100644
--- a/hms-support/hms-core/src/test/scala/net/shrine/hms/authorization/HmsDataStewardAuthorizationServiceTest.scala
+++ b/hms-support/hms-core/src/test/scala/net/shrine/hms/authorization/HmsDataStewardAuthorizationServiceTest.scala
@@ -1,162 +1,162 @@
package net.shrine.hms.authorization
import net.shrine.util.ShouldMatchersForJUnit
import org.junit.Test
import net.shrine.protocol.ApprovedTopic
import org.scalatest.mock.EasyMockSugar
import net.shrine.authentication.AuthenticationResult
import net.shrine.authentication.Authenticator
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.ReadApprovedQueryTopicsRequest
import net.shrine.protocol.ErrorResponse
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.protocol.ReadApprovedQueryTopicsResponse
/**
* @author Bill Simons
- * @date 1/30/12
- * @link http://cbmi.med.harvard.edu
- * @link http://chip.org
+ * @since 1/30/12
+ * @see http://cbmi.med.harvard.edu
+ * @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
- * @link http://www.gnu.org/licenses/lgpl.html
+ * @see http://www.gnu.org/licenses/lgpl.html
*/
final class HmsDataStewardAuthorizationServiceTest extends ShouldMatchersForJUnit {
@Test
def testIdentifyEcommonsUsername: Unit = {
import HmsDataStewardAuthorizationService.identifyEcommonsUsername
import AuthenticationResult._
identifyEcommonsUsername(NotAuthenticated("", "", "")) should be(None)
val ecommonsId = "foo"
identifyEcommonsUsername(Authenticated("", ecommonsId)) should be(Some(ecommonsId))
}
import HmsDataStewardAuthorizationServiceTest._
import scala.concurrent.duration._
private val authn = AuthenticationInfo("d", "u", Credential("p", false))
@Test
def testReadApprovedEntriesNotAuthenticated {
val service = HmsDataStewardAuthorizationService(null, NeverAuthenticatesAuthenticator)
val result = service.readApprovedEntries(ReadApprovedQueryTopicsRequest("projectId", 0.minutes, authn, authn.username))
val Left(errorResponse: ErrorResponse) = result
errorResponse.errorMessage should not be (null)
}
@Test
def testReadApprovedEntriesAuthenticated {
val topic = ApprovedTopic(123L, "blarg")
val ecommonsUsername = "abc123"
val mockSheriffClient = MockSheriffClient(topics = Seq(topic))
val service = HmsDataStewardAuthorizationService(mockSheriffClient, AlwaysAuthenticatesAuthenticator(ecommonsUsername))
val result = service.readApprovedEntries(ReadApprovedQueryTopicsRequest("projectId", 0.minutes, authn, authn.username))
val Right(ReadApprovedQueryTopicsResponse(Seq(actualTopic))) = result
actualTopic should equal(topic)
mockSheriffClient.Params.user should be(null)
mockSheriffClient.Params.topicId should be(null)
mockSheriffClient.Params.queryText should be(null)
mockSheriffClient.Params.ecommonsUsername should be(ecommonsUsername)
}
@Test
def testAuthorizeRunQueryRequestNotAuthenticated {
val service = HmsDataStewardAuthorizationService(null, NeverAuthenticatesAuthenticator)
- def doTest(topicId: Option[String]): Unit = {
- val result = service.authorizeRunQueryRequest(RunQueryRequest("projectId", 0.minutes, authn, 12345L, topicId, Set.empty, QueryDefinition("foo", Term("foo"))))
+ def doTest(topicId: Option[String],topicName:Option[String]): Unit = {
+ val result = service.authorizeRunQueryRequest(RunQueryRequest("projectId", 0.minutes, authn, 12345L, topicId, topicName, Set.empty, QueryDefinition("foo", Term("foo"))))
result.isAuthorized should be(false)
}
- doTest(None)
- doTest(Some("topicId"))
+ doTest(None,None)
+ doTest(Some("topicId"),Some("Topic Name"))
}
@Test
def testAuthorizeRunQueryRequestAuthenticated {
- def doTest(isAuthorized: Boolean, topicId: Option[String]): Unit = {
+ def doTest(isAuthorized: Boolean, topicId: Option[String], topicName:Option[String]): Unit = {
val ecommonsUsername = "abc123"
val queryDef = QueryDefinition("foo", Term("foo"))
val mockSheriffClient = MockSheriffClient(authorized = isAuthorized)
val service = HmsDataStewardAuthorizationService(mockSheriffClient, AlwaysAuthenticatesAuthenticator(ecommonsUsername))
- val result = service.authorizeRunQueryRequest(RunQueryRequest("projectId", 0.minutes, authn, 12345L, topicId, Set.empty, queryDef))
+ val result = service.authorizeRunQueryRequest(RunQueryRequest("projectId", 0.minutes, authn, 12345L, topicId, topicName, Set.empty, queryDef))
val expectedIsAuthorized = isAuthorized && topicId.isDefined
result.isAuthorized should be(expectedIsAuthorized)
if (topicId.isDefined) {
mockSheriffClient.Params.user should equal(ecommonsUsername)
mockSheriffClient.Params.topicId should equal(topicId.get)
mockSheriffClient.Params.queryText should equal(queryDef.toI2b2String)
mockSheriffClient.Params.ecommonsUsername should be(null)
} else {
mockSheriffClient.Params.user should be(null)
mockSheriffClient.Params.topicId should be(null)
mockSheriffClient.Params.queryText should be(null)
mockSheriffClient.Params.ecommonsUsername should be(null)
}
}
- doTest(true, Some("topic123"))
- doTest(false, Some("topic123"))
- doTest(true, None)
- doTest(false, None)
+ doTest(true, Some("topic123"), Some("Topic Name"))
+ doTest(false, Some("topic123"), Some("Topic Name"))
+ doTest(true, None, None)
+ doTest(false, None, None)
}
}
object HmsDataStewardAuthorizationServiceTest {
object NeverAuthenticatesAuthenticator extends Authenticator {
override def authenticate(authn: AuthenticationInfo) = AuthenticationResult.NotAuthenticated(authn.domain, authn.username, "foo")
}
final case class AlwaysAuthenticatesAuthenticator(ecommonsUsername: String) extends Authenticator {
override def authenticate(authn: AuthenticationInfo) = AuthenticationResult.Authenticated(authn.domain, ecommonsUsername)
}
final case class MockSheriffClient(authorized: Boolean = false, topics: Seq[ApprovedTopic] = Nil) extends SheriffClient {
object Params {
var ecommonsUsername: String = _
var user: String = _
var topicId: String = _
var queryText: String = _
}
override def getApprovedEntries(ecommonsUsername: String): Seq[ApprovedTopic] = {
Params.ecommonsUsername = ecommonsUsername
topics
}
override def isAuthorized(user: String, topicId: String, queryText: String): Boolean = {
Params.user = user
Params.topicId = topicId
Params.queryText = queryText
authorized
}
}
}
\ No newline at end of file
diff --git a/hub/broadcaster-aggregator/src/test/scala/net/shrine/aggregation/AggregatorsTest.scala b/hub/broadcaster-aggregator/src/test/scala/net/shrine/aggregation/AggregatorsTest.scala
index 36d0ebeca..3bde4a3c5 100644
--- a/hub/broadcaster-aggregator/src/test/scala/net/shrine/aggregation/AggregatorsTest.scala
+++ b/hub/broadcaster-aggregator/src/test/scala/net/shrine/aggregation/AggregatorsTest.scala
@@ -1,42 +1,42 @@
package net.shrine.aggregation
import net.shrine.util.ShouldMatchersForJUnit
import org.junit.Test
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.protocol.RunQueryRequest
/**
* @author clint
- * @date Mar 14, 2013
+ * @since Mar 14, 2013
*/
final class AggregatorsTest extends ShouldMatchersForJUnit {
@Test
- def testForRunQueryRequest {
+ def testForRunQueryRequest() {
- val authn = AuthenticationInfo("some-domain", "some-user", Credential("some-password", false))
+ val authn = AuthenticationInfo("some-domain", "some-user", Credential("some-password", isToken = false))
val projectId = "projectId"
val queryDef = QueryDefinition("yo", Term("foo"))
import scala.concurrent.duration._
- val request = RunQueryRequest(projectId, 1.millisecond, authn, 0L, Some("topicId"), Set.empty, queryDef)
+ val request = RunQueryRequest(projectId, 1.millisecond, authn, 0L, Some("topicId"), Some("Topic Name"), Set.empty, queryDef)
def doTestRunQueryAggregatorFor(addAggregatedResult: Boolean) {
val aggregator = Aggregators.forRunQueryRequest(addAggregatedResult)(request)
- aggregator should not be (null)
+ aggregator should not be null
aggregator.queryId should be(-1L)
aggregator.groupId should be(projectId)
aggregator.userId should be(authn.username)
aggregator.requestQueryDefinition should be(queryDef)
aggregator.addAggregatedResult should be(addAggregatedResult)
}
doTestRunQueryAggregatorFor(true)
doTestRunQueryAggregatorFor(false)
}
}
\ No newline at end of file
diff --git a/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/AdapterClientBroadcasterLoggingTest.scala b/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/AdapterClientBroadcasterLoggingTest.scala
index 3836dd459..2c51990f0 100644
--- a/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/AdapterClientBroadcasterLoggingTest.scala
+++ b/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/AdapterClientBroadcasterLoggingTest.scala
@@ -1,169 +1,169 @@
package net.shrine.broadcaster
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.BroadcastMessage
import net.shrine.protocol.DeleteQueryRequest
import org.junit.Test
import net.shrine.protocol.NodeId
import net.shrine.adapter.client.InJvmAdapterClient
import net.shrine.protocol.Result
import scala.concurrent.Future
import net.shrine.adapter.client.AdapterClient
import net.shrine.protocol.DeleteQueryResponse
import net.shrine.aggregation.DeleteQueryAggregator
import net.shrine.util.ShouldMatchersForJUnit
import scala.concurrent.Await
import net.shrine.dao.squeryl.SquerylEntryPoint
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.ResultOutputType
import net.shrine.protocol.query.Term
import net.shrine.protocol.query.Or
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.RunQueryResponse
import net.shrine.protocol.QueryResult
import net.shrine.util.XmlDateHelper
import net.shrine.aggregation.RunQueryAggregator
import net.shrine.protocol.AggregatedRunQueryResponse
import net.shrine.protocol.AggregatedRunQueryResponse
import net.shrine.protocol.ShrineResponse
import net.shrine.protocol.ErrorResponse
import net.shrine.broadcaster.dao.model.squeryl.SquerylHubQueryResultRow
import net.shrine.broadcaster.dao.model.HubQueryResultRow
import net.shrine.broadcaster.dao.model.HubQueryStatus
/**
* @author clint
* @date Dec 15, 2014
*/
final class AdapterClientBroadcasterLoggingTest extends AbstractSquerylHubDaoTest with ShouldMatchersForJUnit {
private def makeBroadcaster(nodes: Set[NodeHandle]): AdapterClientBroadcaster = AdapterClientBroadcaster(nodes, dao)
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
private final class TestAdapterClient(toReturn: => Result) extends AdapterClient {
override def query(message: BroadcastMessage): Future[Result] = Future { toReturn }
}
private object TestAdapterClient {
def apply(toReturn: => Result): TestAdapterClient = new TestAdapterClient(toReturn)
}
private val authn = AuthenticationInfo("domain", "username", Credential("asdasd", false))
private val queryDef = QueryDefinition("foo", Or(Term("x"), Term("y")))
private val broadcastMessageDelete = {
BroadcastMessage(authn, DeleteQueryRequest("projectId", 12345.milliseconds, authn, 12345L))
}
import ResultOutputType.PATIENT_COUNT_XML
private val broadcastMessageRunQuery = {
- BroadcastMessage(authn, RunQueryRequest("projectId", 12345.milliseconds, authn, -1L, None, Set(PATIENT_COUNT_XML), queryDef))
+ BroadcastMessage(authn, RunQueryRequest("projectId", 12345.milliseconds, authn, -1L, None, None, Set(PATIENT_COUNT_XML), queryDef))
}
private val deleteQueryAggregator = new DeleteQueryAggregator
import SquerylEntryPoint._
@Test
def testShouldntLogAllNodesSucceed: Unit = afterCreatingTables {
val workingNodes = Set(
NodeHandle(NodeId("X"), TestAdapterClient(Result(NodeId("X"), 1.second, DeleteQueryResponse(12345L)))),
NodeHandle(NodeId("Y"), TestAdapterClient(Result(NodeId("Y"), 1.second, DeleteQueryResponse(12345L)))))
doTestShouldntLog(workingNodes)
}
@Test
def testShouldntLogSomeNodesSucceed: Unit = afterCreatingTables {
val nodes = Set(
NodeHandle(NodeId("X"), TestAdapterClient(Result(NodeId("X"), 1.second, DeleteQueryResponse(12345L)))),
NodeHandle(NodeId("Y"), TestAdapterClient(throw new Exception)))
doTestShouldntLog(nodes)
}
@Test
def testShouldntLogNoNodesSucceed: Unit = afterCreatingTables {
val failingNodes = Set(
NodeHandle(NodeId("X"), TestAdapterClient(throw new Exception)),
NodeHandle(NodeId("Y"), TestAdapterClient(throw new Exception)))
doTestShouldntLog(failingNodes, classOf[ErrorResponse])
}
private def doTestShouldntLog(nodeHandles: Set[NodeHandle], expectedAggregatedResponseType: Class[_ <: ShrineResponse] = classOf[DeleteQueryResponse]): Unit = {
val broadcaster = makeBroadcaster(nodeHandles)
val responses = Await.result(broadcaster.broadcast(broadcastMessageDelete).responses, Duration.Inf)
responses.size should equal(nodeHandles.size)
//Only log RunQueryRequests
list(queryRows) should be(Nil)
//Only log RunQueryRequests
list(queryResultRows) should be(Nil)
}
import net.shrine.broadcaster.dao.model.{HubQueryStatus => hqs}
@Test
def testShouldLogAllNodesSucceed: Unit = doTestShouldLog(Map("X" -> hqs.Success, "Y" -> hqs.Success))
@Test
def testShouldLogSomeNodesSucceed: Unit = doTestShouldLog(Map("X" -> hqs.Success, "Y" -> hqs.Failure))
@Test
def testShouldLogNoNodesSucceed: Unit = doTestShouldLog(Map("X" -> hqs.Failure, "Y" -> hqs.Failure))
private def doTestShouldLog(expectedStatusesByNodeName: Map[String, HubQueryStatus]): Unit = afterCreatingTables {
val queryResult = QueryResult(99L, 11L,Some(PATIENT_COUNT_XML), 42L, Some(XmlDateHelper.now), Some(XmlDateHelper.now), Some("desc"), QueryResult.StatusType.Finished, Some("status"))
val nodes: Set[NodeHandle] = expectedStatusesByNodeName.map { case (nodeName, status) =>
val adapterClient = status match {
case hqs.Success => TestAdapterClient(Result(NodeId(nodeName), 1.second, RunQueryResponse(12345L, XmlDateHelper.now, "uid", "gid", queryDef, 42L, queryResult)))
case hqs.Failure => TestAdapterClient(throw new Exception)
}
NodeHandle(NodeId(nodeName), adapterClient)
}.toSet
val broadcaster = makeBroadcaster(nodes)
val responses = Await.result(broadcaster.broadcast(broadcastMessageRunQuery).responses, Duration.Inf)
responses.size should equal(expectedStatusesByNodeName.size)
val Seq(queryRow) = list(queryRows).map(_.toHubQueryRow)
queryRow.networkQueryId should be(broadcastMessageRunQuery.requestId)
queryRow.queryDefinition should be(queryDef)
queryRow.domain should be(authn.domain)
queryRow.username should be(authn.username)
queryRow.time should not be(null)
val resultRows @ Seq(resultRow1, resultRow2) = list(queryResultRows).map(_.toHubQueryResultRow)
resultRow1.networkQueryId should be(broadcastMessageRunQuery.requestId)
resultRow2.networkQueryId should be(broadcastMessageRunQuery.requestId)
val resultRowsByNode: Map[String, HubQueryResultRow] = resultRows.map(row => row.nodeName -> row).toMap
resultRowsByNode.keySet should be(expectedStatusesByNodeName.keySet)
for {
(nodeName, expectedStatus) <- expectedStatusesByNodeName
} {
resultRowsByNode(nodeName).status should be(expectedStatus)
}
resultRow1.timestamp should not be(null)
resultRow2.timestamp should not be(null)
}
}
\ No newline at end of file
diff --git a/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/BroadcastAndAggregationServiceTest.scala b/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/BroadcastAndAggregationServiceTest.scala
index 101c64449..a6678546c 100644
--- a/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/BroadcastAndAggregationServiceTest.scala
+++ b/hub/broadcaster-aggregator/src/test/scala/net/shrine/broadcaster/BroadcastAndAggregationServiceTest.scala
@@ -1,174 +1,174 @@
package net.shrine.broadcaster
import net.shrine.util.ShouldMatchersForJUnit
import org.junit.Test
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.protocol.BroadcastMessage
import net.shrine.protocol.ShrineResponse
import net.shrine.aggregation.Aggregator
import scala.concurrent.Future
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.aggregation.DeleteQueryAggregator
import net.shrine.aggregation.RunQueryAggregator
import net.shrine.aggregation.ReadQueryResultAggregator
/**
* @author clint
- * @date Mar 14, 2013
+ * @since Mar 14, 2013
*/
final class BroadcastAndAggregationServiceTest extends ShouldMatchersForJUnit {
import BroadcastAndAggregationServiceTest._
- private val authn = AuthenticationInfo("some-domain", "some-user", Credential("some-password", false))
+ private val authn = AuthenticationInfo("some-domain", "some-user", Credential("some-password", isToken = false))
private val queryDef = QueryDefinition("yo", Term("foo"))
import scala.concurrent.duration._
@Test
- def testSendAndAggregateShrineRequest {
+ def testSendAndAggregateShrineRequest() {
val service = new TestBroadcastAndAggregationService
{
val req = DeleteQueryRequest("projectId", 1.millisecond, authn, 123L)
val aggregator = new DeleteQueryAggregator
- val networkAuthn = AuthenticationInfo("d", "u", Credential("p", false))
+ val networkAuthn = AuthenticationInfo("d", "u", Credential("p", isToken = false))
- service.sendAndAggregate(networkAuthn, req, aggregator, true)
+ service.sendAndAggregate(networkAuthn, req, aggregator, shouldBroadcast = true)
service.args.shouldBroadcast should be(Some(true))
- service.sendAndAggregate(networkAuthn, req, aggregator, false)
+ service.sendAndAggregate(networkAuthn, req, aggregator, shouldBroadcast = false)
service.args.shouldBroadcast should be(Some(false))
service.args.aggregator should be(aggregator)
service.args.message.networkAuthn should be(networkAuthn)
service.args.message.request should be(req)
- (service.args.message.requestId > 0) should be(true)
+ (service.args.message.requestId > 0) should be(right = true)
}
{
val invalidQueryId = -1L
- val req = RunQueryRequest("projectId", 1.millisecond, authn, invalidQueryId, Some("topicId"), Set.empty, queryDef)
+ val req = RunQueryRequest("projectId", 1.millisecond, authn, invalidQueryId, Some("topicId"), Some("Topic Name"), Set.empty, queryDef)
val aggregator = new RunQueryAggregator(invalidQueryId, authn.username, authn.domain, queryDef, true)
- val networkAuthn = AuthenticationInfo("d", "u", Credential("p", false))
+ val networkAuthn = AuthenticationInfo("d", "u", Credential("p", isToken = false))
- service.sendAndAggregate(networkAuthn, req, aggregator, true)
+ service.sendAndAggregate(networkAuthn, req, aggregator, shouldBroadcast = true)
service.args.shouldBroadcast should be(Some(true))
- (service.args.message.requestId > 0) should be(true)
- service.args.message.request should not be(req)
+ (service.args.message.requestId > 0) should be(right = true)
+ service.args.message.request should not be req
service.args.message.request.asInstanceOf[RunQueryRequest].networkQueryId should be(service.args.message.requestId)
service.args.message.networkAuthn should be(networkAuthn)
- service.args.aggregator should not be(aggregator)
+ service.args.aggregator should not be aggregator
service.args.aggregator.asInstanceOf[RunQueryAggregator].queryId should be(service.args.message.requestId)
}
}
@Test
- def testAddQueryIdAggregator {
+ def testAddQueryIdAggregator() {
val service = new TestBroadcastAndAggregationService
{
val aggregator = new DeleteQueryAggregator
val munged = service.addQueryId(null, aggregator)
- (munged eq aggregator) should be(true)
+ (munged eq aggregator) should be(right = true)
}
{
val aggregator = new RunQueryAggregator(-1L, authn.username, authn.domain, queryDef, true)
val message = BroadcastMessage(999L, authn, null)
val munged = service.addQueryId(message, aggregator).asInstanceOf[RunQueryAggregator]
munged.queryId should be(message.requestId)
munged.userId should equal(aggregator.userId)
munged.groupId should equal(aggregator.groupId)
munged.requestQueryDefinition should equal(aggregator.requestQueryDefinition)
munged.addAggregatedResult should equal(aggregator.addAggregatedResult)
}
def doTestWithReadQueryResultAggregator(showAggregation: Boolean) {
val aggregator = new ReadQueryResultAggregator(-1L, showAggregation)
val message = BroadcastMessage(999L, authn, null)
val munged = service.addQueryId(message, aggregator).asInstanceOf[ReadQueryResultAggregator]
- munged should not be(aggregator)
+ munged should not be aggregator
munged.shrineNetworkQueryId should be(message.requestId)
munged.showAggregation should be(aggregator.showAggregation)
}
doTestWithReadQueryResultAggregator(true)
doTestWithReadQueryResultAggregator(false)
}
@Test
- def testAddQueryIdShrineRequest {
+ def testAddQueryIdShrineRequest() {
val service = new TestBroadcastAndAggregationService
{
val req = DeleteQueryRequest("projectId", 1.millisecond, authn, 123L)
val (queryIdOption, transformedReq) = service.addQueryId(req)
queryIdOption should be(None)
transformedReq should be(req)
}
{
- val req = RunQueryRequest("projectId", 1.millisecond, authn, -1L, Some("topicId"), Set.empty, QueryDefinition("yo", Term("foo")))
+ val req = RunQueryRequest("projectId", 1.millisecond, authn, -1L, Some("topicId"), Some("Topic Name"), Set.empty, QueryDefinition("yo", Term("foo")))
val (queryIdOption, transformedReq: RunQueryRequest) = service.addQueryId(req)
- queryIdOption should not be(None)
+ queryIdOption should not be None
- (queryIdOption.get > 0) should be(true)
+ (queryIdOption.get > 0) should be(right = true)
transformedReq.networkQueryId should be(queryIdOption.get)
transformedReq.projectId should be(req.projectId)
transformedReq.waitTime should be(req.waitTime)
transformedReq.authn should be(req.authn)
transformedReq.topicId should be(req.topicId)
transformedReq.outputTypes should be(req.outputTypes)
transformedReq.queryDefinition should be(req.queryDefinition)
}
}
}
object BroadcastAndAggregationServiceTest {
private final class TestBroadcastAndAggregationService extends BroadcastAndAggregationService {
object args {
var message: BroadcastMessage = _
var aggregator: Aggregator = _
var shouldBroadcast: Option[Boolean] = None
}
override def sendAndAggregate(message: BroadcastMessage, aggregator: Aggregator, shouldBroadcast: Boolean): Future[ShrineResponse] = {
args.message = message
args.aggregator = aggregator
args.shouldBroadcast = Some(shouldBroadcast)
Future.successful(null)
}
}
}
\ No newline at end of file
diff --git a/integration/src/test/scala/net/shrine/integration/I2b2ShrineClient.scala b/integration/src/test/scala/net/shrine/integration/I2b2ShrineClient.scala
index f8fab7e2c..8b840fa4e 100644
--- a/integration/src/test/scala/net/shrine/integration/I2b2ShrineClient.scala
+++ b/integration/src/test/scala/net/shrine/integration/I2b2ShrineClient.scala
@@ -1,88 +1,88 @@
package net.shrine.integration
import net.shrine.client.ShrineClient
import net.shrine.crypto.TrustParam
import net.shrine.protocol.AuthenticationInfo
import net.shrine.util.XmlDateHelper
import net.shrine.client.Poster
import net.shrine.protocol.ResultOutputType
import scala.xml.NodeSeq
import net.shrine.protocol.AggregatedReadTranslatedQueryDefinitionResponse
import net.shrine.protocol.ReadQueryDefinitionResponse
import net.shrine.protocol.UnFlagQueryResponse
import net.shrine.protocol.ReadPdoResponse
import net.shrine.protocol.RenameQueryResponse
import net.shrine.protocol.ReadQueryInstancesResponse
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.AggregatedRunQueryResponse
import net.shrine.protocol.FlagQueryResponse
import net.shrine.protocol.DeleteQueryResponse
import net.shrine.protocol.ReadPreviousQueriesResponse
import net.shrine.protocol.ReadApprovedQueryTopicsResponse
import net.shrine.protocol.AggregatedReadInstanceResultsResponse
import net.shrine.protocol.AggregatedReadQueryResultResponse
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.client.HttpResponse
import net.shrine.protocol.FlagQueryRequest
import net.shrine.serialization.I2b2Marshaller
import net.shrine.protocol.UnFlagQueryRequest
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.RunQueryResponse
import net.shrine.protocol.DefaultBreakdownResultOutputTypes
import scala.xml.Node
import scala.xml.XML
import net.shrine.util.XmlUtil
final case class I2b2ShrineClient(poster: Poster, projectId: String, authorization: AuthenticationInfo) extends ShrineClient {
import scala.concurrent.duration._
override def readApprovedQueryTopics(userId: String, shouldBroadcast: Boolean): ReadApprovedQueryTopicsResponse = ???
override def readPreviousQueries(userId: String, fetchSize: Int, shouldBroadcast: Boolean): ReadPreviousQueriesResponse = ???
override def runQuery(topicId: String, outputTypes: Set[ResultOutputType], queryDefinition: QueryDefinition, shouldBroadcast: Boolean): AggregatedRunQueryResponse = {
- val req = RunQueryRequest(projectId, 1.minute, authorization, -1, None, outputTypes, queryDefinition)
+ val req = RunQueryRequest(projectId, 1.minute, authorization, -1, None, None, outputTypes, queryDefinition)
def stripWhitespace(xml: String): String = XmlUtil.stripWhitespace(XML.loadString(xml)).toString
doSend(req, xml => AggregatedRunQueryResponse.fromI2b2String(DefaultBreakdownResultOutputTypes.toSet)(stripWhitespace(xml)).get)
}
override def readQueryInstances(queryId: Long, shouldBroadcast: Boolean): ReadQueryInstancesResponse = ???
override def readInstanceResults(instanceId: Long, shouldBroadcast: Boolean): AggregatedReadInstanceResultsResponse = ???
override def readPdo(patientSetCollId: String, optionsXml: NodeSeq, shouldBroadcast: Boolean): ReadPdoResponse = ???
override def readQueryDefinition(queryId: Long, shouldBroadcast: Boolean): ReadQueryDefinitionResponse = ???
override def deleteQuery(queryId: Long, shouldBroadcast: Boolean): DeleteQueryResponse = {
val req = DeleteQueryRequest(projectId, 1.minute, authorization, queryId)
doSend(req, DeleteQueryResponse.fromI2b2)
}
override def renameQuery(queryId: Long, queryName: String, shouldBroadcast: Boolean): RenameQueryResponse = ???
override def readTranslatedQueryDefinition(queryDef: QueryDefinition, shouldBroadcast: Boolean): AggregatedReadTranslatedQueryDefinitionResponse = ???
override def flagQuery(networkQueryId: Long, message: Option[String], shouldBroadcast: Boolean): FlagQueryResponse = {
val req = FlagQueryRequest(projectId, 1.minute, authorization, networkQueryId, message)
doSend(req, FlagQueryResponse.fromI2b2(_).get)
}
override def unFlagQuery(networkQueryId: Long, shouldBroadcast: Boolean): UnFlagQueryResponse = {
val req = UnFlagQueryRequest(projectId, 1.minute, authorization, networkQueryId)
doSend(req, UnFlagQueryResponse.fromI2b2(_).get)
}
override def readQueryResult(queryId: Long, shouldBroadcast: Boolean): AggregatedReadQueryResultResponse = ???
private def doSend[R](req: I2b2Marshaller, unmarshal: String => R): R = {
val HttpResponse(_, i2b2Resp) = poster.post(req.toI2b2String)
unmarshal(i2b2Resp)
}
}
\ No newline at end of file
diff --git a/integration/src/test/scala/net/shrine/integration/NetworkSimulationTest.scala b/integration/src/test/scala/net/shrine/integration/NetworkSimulationTest.scala
index b3cfe58e1..74d144e84 100644
--- a/integration/src/test/scala/net/shrine/integration/NetworkSimulationTest.scala
+++ b/integration/src/test/scala/net/shrine/integration/NetworkSimulationTest.scala
@@ -1,336 +1,337 @@
package net.shrine.integration
import net.shrine.log.Loggable
import scala.concurrent.Future
import scala.concurrent.duration.DurationInt
import org.junit.Test
import net.shrine.util.ShouldMatchersForJUnit
import net.shrine.adapter.AdapterMap
import net.shrine.adapter.DeleteQueryAdapter
import net.shrine.adapter.client.AdapterClient
import net.shrine.adapter.dao.squeryl.AbstractSquerylAdapterTest
import net.shrine.adapter.service.AdapterRequestHandler
import net.shrine.adapter.service.AdapterService
import net.shrine.broadcaster.AdapterClientBroadcaster
import net.shrine.broadcaster.NodeHandle
import net.shrine.crypto.DefaultSignerVerifier
import net.shrine.crypto.TestKeystore
import net.shrine.protocol.{HiveCredentials, AuthenticationInfo, BroadcastMessage, Credential, DeleteQueryRequest, DeleteQueryResponse, NodeId, Result, RunQueryRequest, CertId, RequestType, FlagQueryRequest, FlagQueryResponse, RawCrcRunQueryResponse, ResultOutputType, QueryResult, RunQueryResponse, AggregatedRunQueryResponse, UnFlagQueryRequest, UnFlagQueryResponse, DefaultBreakdownResultOutputTypes}
import net.shrine.service.ShrineService
import net.shrine.broadcaster.SigningBroadcastAndAggregationService
import net.shrine.broadcaster.InJvmBroadcasterClient
import net.shrine.adapter.FlagQueryAdapter
import net.shrine.protocol.query.Term
import net.shrine.adapter.RunQueryAdapter
import net.shrine.client.Poster
import net.shrine.client.HttpClient
import net.shrine.client.HttpResponse
import net.shrine.adapter.translators.QueryDefinitionTranslator
import net.shrine.adapter.translators.ExpressionTranslator
import net.shrine.util.XmlDateHelper
import net.shrine.adapter.ReadQueryResultAdapter
import net.shrine.protocol.query.QueryDefinition
import net.shrine.adapter.UnFlagQueryAdapter
import net.shrine.crypto.SigningCertStrategy
/**
* @author clint
* @since Nov 27, 2013
*
* An in-JVM simulation of a Shrine network with one hub and 4 doanstream adapters.
*
* The hub and adapters are wired up with mock AdapterClients that do in-JVM communication via method calls
* instead of remotely.
*
* The adapters are configured to respond with valid results for DeleteQueryRequests
* only. Other requests could be handled, but that would not provide benefit to offset the effort of wiring
* up more and more-complex Adapters.
*
* The test network is queried, and the final result, as well as the state of each adapter, is inspected to
* ensure that the right messages were sent between elements of the system.
*
*/
final class NetworkSimulationTest extends AbstractSquerylAdapterTest with ShouldMatchersForJUnit {
private val certCollection = TestKeystore.certCollection
private lazy val myCertId: CertId = certCollection.myCertId.get
private lazy val signerVerifier = new DefaultSignerVerifier(certCollection)
private val domain = "test-domain"
private val username = "test-username"
private val password = "test-password"
import NetworkSimulationTest._
import scala.concurrent.duration._
private def deleteQueryAdapter: DeleteQueryAdapter = new DeleteQueryAdapter(dao)
private def flagQueryAdapter: FlagQueryAdapter = new FlagQueryAdapter(dao)
private def unFlagQueryAdapter: UnFlagQueryAdapter = new UnFlagQueryAdapter(dao)
private def mockPoster = Poster("http://example.com", new HttpClient {
override def post(input: String, url: String): HttpResponse = ???
})
private val hiveCredentials = HiveCredentials("d", "u", "pwd", "pid")
private def queuesQueriesRunQueryAdapter: RunQueryAdapter = {
val translator = new QueryDefinitionTranslator(new ExpressionTranslator(Map("n1" -> Set("l1"))))
RunQueryAdapter(
mockPoster,
dao,
hiveCredentials,
translator,
10000,
doObfuscation = false,
runQueriesImmediately = false,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
}
private def immediatelyRunsQueriesRunQueryAdapter(setSize: Long): RunQueryAdapter = {
val mockCrcPoster = Poster("http://example.com", new HttpClient {
override def post(input: String, url: String): HttpResponse = {
val req = RunQueryRequest.fromI2b2String(DefaultBreakdownResultOutputTypes.toSet)(input).get
val now = XmlDateHelper.now
val queryResult = QueryResult(1L, 42L, Some(ResultOutputType.PATIENT_COUNT_XML), setSize, Some(now), Some(now), Some("desc"), QueryResult.StatusType.Finished, Some("status"))
val mockCrcXml = RawCrcRunQueryResponse(req.networkQueryId, XmlDateHelper.now, req.authn.username, req.projectId, req.queryDefinition, 42L, Map(ResultOutputType.PATIENT_COUNT_XML -> Seq(queryResult))).toI2b2String
HttpResponse.ok(mockCrcXml)
}
})
queuesQueriesRunQueryAdapter.copy(poster = mockCrcPoster, runQueriesImmediately = true)
}
private def readQueryResultAdapter(setSize: Long): ReadQueryResultAdapter = {
new ReadQueryResultAdapter(
mockPoster,
hiveCredentials,
dao,
doObfuscation = false,
DefaultBreakdownResultOutputTypes.toSet,
collectAdapterAudit = false
)
}
private lazy val adaptersByNodeId: Seq[(NodeId, MockAdapterRequestHandler)] = {
import NodeName._
import RequestType.{ MasterDeleteRequest => MasterDeleteRequestRT, FlagQueryRequest => FlagQueryRequestRT, QueryDefinitionRequest => RunQueryRT, GetQueryResult => ReadQueryResultRT, UnFlagQueryRequest => UnFlagQueryRequestRT }
(for {
(childName, setSize) <- Seq((A, 1L), (B, 2L), (C, 3L), (D, 4L))
} yield {
val nodeId = NodeId(childName.name)
val maxSignatureAge = 1.hour
val adapterMap = AdapterMap(Map(
MasterDeleteRequestRT -> deleteQueryAdapter,
FlagQueryRequestRT -> flagQueryAdapter,
UnFlagQueryRequestRT -> unFlagQueryAdapter,
RunQueryRT -> queuesQueriesRunQueryAdapter,
ReadQueryResultRT -> readQueryResultAdapter(setSize)))
nodeId -> MockAdapterRequestHandler(new AdapterService(nodeId, signerVerifier, maxSignatureAge, adapterMap))
})
}
private lazy val shrineService: ShrineService = {
val destinations: Set[NodeHandle] = {
(for {
(nodeId, adapterRequestHandler) <- adaptersByNodeId
} yield {
NodeHandle(nodeId, MockAdapterClient(nodeId, adapterRequestHandler))
}).toSet
}
ShrineService(
"example.com",
MockAuditDao,
MockAuthenticator,
MockQueryAuthorizationService,
true,
SigningBroadcastAndAggregationService(InJvmBroadcasterClient(AdapterClientBroadcaster(destinations, MockHubDao)), signerVerifier, SigningCertStrategy.Attach),
1.hour,
DefaultBreakdownResultOutputTypes.toSet,
false)
}
@Test
def testSimulatedNetwork = afterCreatingTables {
val authn = AuthenticationInfo(domain, username, Credential(password, false))
val masterId = 12345L
import scala.concurrent.duration._
val req = DeleteQueryRequest("some-project-id", 1.second, authn, masterId)
val resp = shrineService.deleteQuery(req, true)
for {
(nodeId, mockAdapter) <- adaptersByNodeId
} {
mockAdapter.lastMessage.networkAuthn.domain should equal(authn.domain)
mockAdapter.lastMessage.networkAuthn.username should equal(authn.username)
mockAdapter.lastMessage.request should equal(req)
mockAdapter.lastResult.response should equal(DeleteQueryResponse(masterId))
}
resp should equal(DeleteQueryResponse(masterId))
}
@Test
def testQueueQuery = afterCreatingTables {
val authn = AuthenticationInfo(domain, username, Credential(password, false))
val topicId = "askldjlkas"
+ val topicName = "Topic Name"
val queryName = "lsadj3028940"
import scala.concurrent.duration._
- val runQueryReq = RunQueryRequest("some-project-id", 1.second, authn, 12345L, Some(topicId), Set(ResultOutputType.PATIENT_COUNT_XML), QueryDefinition(queryName, Term("n1")))
+ val runQueryReq = RunQueryRequest("some-project-id", 1.second, authn, 12345L, Some(topicId), Some(topicName), Set(ResultOutputType.PATIENT_COUNT_XML), QueryDefinition(queryName, Term("n1")))
val aggregatedRunQueryResp = shrineService.runQuery(runQueryReq, true).asInstanceOf[AggregatedRunQueryResponse]
var broadcastMessageId: Option[Long] = None
//Broadcast the original run query request; all nodes should queue the query
for {
(nodeId, mockAdapter) <- adaptersByNodeId
} {
broadcastMessageId = Option(mockAdapter.lastMessage.requestId)
mockAdapter.lastMessage.networkAuthn.domain should equal(authn.domain)
mockAdapter.lastMessage.networkAuthn.username should equal(authn.username)
val lastReq = mockAdapter.lastMessage.request.asInstanceOf[RunQueryRequest]
lastReq.authn should equal(runQueryReq.authn)
lastReq.requestType should equal(runQueryReq.requestType)
lastReq.waitTime should equal(runQueryReq.waitTime)
lastReq.networkQueryId should equal(mockAdapter.lastMessage.requestId)
lastReq.outputTypes should equal(runQueryReq.outputTypes)
lastReq.projectId should equal(runQueryReq.projectId)
lastReq.queryDefinition should equal(runQueryReq.queryDefinition)
lastReq.topicId should equal(runQueryReq.topicId)
val runQueryResp = mockAdapter.lastResult.response.asInstanceOf[RunQueryResponse]
runQueryResp.queryId should equal(-1L)
runQueryResp.singleNodeResult.statusType should equal(QueryResult.StatusType.Held)
runQueryResp.singleNodeResult.setSize should equal(-1L)
}
aggregatedRunQueryResp.queryId should equal(broadcastMessageId.get)
aggregatedRunQueryResp.results.map(_.setSize) should equal(Seq(-1L, -1L, -1L, -1L, -4L))
}
@Test
def testFlagQuery = afterCreatingTables {
val authn = AuthenticationInfo(domain, username, Credential(password, false))
val masterId = 12345L
import scala.concurrent.duration._
val networkQueryId = 9999L
val name = "some query"
val expr = Term("foo")
val fooQuery = QueryDefinition(name,expr)
dao.insertQuery(masterId.toString, networkQueryId, authn, fooQuery, isFlagged = false, hasBeenRun = true, flagMessage = None)
dao.findQueryByNetworkId(networkQueryId).get.isFlagged should be(false)
dao.findQueryByNetworkId(networkQueryId).get.hasBeenRun should be(true)
dao.findQueryByNetworkId(networkQueryId).get.flagMessage should be(None)
val req = FlagQueryRequest("some-project-id", 1.second, authn, networkQueryId, Some("foo"))
val resp = shrineService.flagQuery(req, true)
resp should equal(FlagQueryResponse)
dao.findQueryByNetworkId(networkQueryId).get.isFlagged should be(true)
dao.findQueryByNetworkId(networkQueryId).get.hasBeenRun should be(true)
dao.findQueryByNetworkId(networkQueryId).get.flagMessage should be(Some("foo"))
}
@Test
def testUnFlagQuery = afterCreatingTables {
val authn = AuthenticationInfo(domain, username, Credential(password, false))
val masterId = 12345L
import scala.concurrent.duration._
val networkQueryId = 9999L
val flagMsg = Some("foo")
val name = "some query"
val expr = Term("foo")
val fooQuery = QueryDefinition(name,expr)
dao.insertQuery(masterId.toString, networkQueryId, authn, fooQuery, isFlagged = true, hasBeenRun = true, flagMessage = flagMsg)
dao.findQueryByNetworkId(networkQueryId).get.isFlagged should be(true)
dao.findQueryByNetworkId(networkQueryId).get.hasBeenRun should be(true)
dao.findQueryByNetworkId(networkQueryId).get.flagMessage should be(flagMsg)
val req = UnFlagQueryRequest("some-project-id", 1.second, authn, networkQueryId)
val resp = shrineService.unFlagQuery(req, true)
resp should equal(UnFlagQueryResponse)
dao.findQueryByNetworkId(networkQueryId).get.isFlagged should be(false)
dao.findQueryByNetworkId(networkQueryId).get.hasBeenRun should be(true)
dao.findQueryByNetworkId(networkQueryId).get.flagMessage should be(None)
}
}
object NetworkSimulationTest {
private final case class MockAdapterClient(nodeId: NodeId, adapter: AdapterRequestHandler) extends AdapterClient with Loggable {
import scala.concurrent.ExecutionContext.Implicits.global
override def query(message: BroadcastMessage): Future[Result] = Future.successful {
debug(s"Invoking Adapter $nodeId with $message")
val result = adapter.handleRequest(message)
debug(s"Got result from $nodeId: $result")
result
}
}
private final case class MockAdapterRequestHandler(delegate: AdapterRequestHandler) extends AdapterRequestHandler {
@volatile var lastMessage: BroadcastMessage = _
@volatile var lastResult: Result = _
override def handleRequest(request: BroadcastMessage): Result = {
lastMessage = request
val result = delegate.handleRequest(request)
lastResult = result
result
}
}
}
diff --git a/qep/service/src/main/scala/net/shrine/service/AbstractShrineService.scala b/qep/service/src/main/scala/net/shrine/service/AbstractShrineService.scala
index 0aa6e4ad8..9b2a42d62 100644
--- a/qep/service/src/main/scala/net/shrine/service/AbstractShrineService.scala
+++ b/qep/service/src/main/scala/net/shrine/service/AbstractShrineService.scala
@@ -1,221 +1,221 @@
package net.shrine.service
import net.shrine.log.Loggable
-import net.shrine.service.audit.{QepAuditDb, QepQueryAuditData}
+import net.shrine.service.audit.QepAuditDb
import net.shrine.service.dao.AuditDao
import net.shrine.authentication.Authenticator
import net.shrine.authorization.QueryAuthorizationService
import net.shrine.broadcaster.BroadcastAndAggregationService
import scala.concurrent.duration.Duration
import net.shrine.util.XmlDateHelper
import scala.concurrent.Future
import scala.concurrent.Await
import net.shrine.protocol.RunQueryRequest
import net.shrine.authorization.AuthorizationResult.NotAuthorized
import net.shrine.protocol.BaseShrineRequest
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.authentication.AuthenticationResult
import net.shrine.authentication.NotAuthenticatedException
import net.shrine.aggregation.RunQueryAggregator
import net.shrine.aggregation.Aggregators
import net.shrine.protocol.BaseShrineResponse
import net.shrine.aggregation.Aggregator
import net.shrine.protocol.ReadQueryInstancesRequest
import net.shrine.protocol.QueryInstance
import net.shrine.protocol.ReadQueryInstancesResponse
import net.shrine.protocol.ReadQueryDefinitionRequest
import net.shrine.aggregation.ReadQueryDefinitionAggregator
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.aggregation.ReadPreviousQueriesAggregator
import net.shrine.aggregation.DeleteQueryAggregator
import net.shrine.aggregation.ReadPdoResponseAggregator
import net.shrine.aggregation.RenameQueryAggregator
import net.shrine.aggregation.ReadInstanceResultsAggregator
import net.shrine.protocol.ReadApprovedQueryTopicsRequest
import net.shrine.protocol.ReadInstanceResultsRequest
import net.shrine.protocol.ReadPreviousQueriesRequest
import net.shrine.protocol.RenameQueryRequest
import net.shrine.protocol.ReadPdoRequest
import net.shrine.protocol.FlagQueryRequest
import net.shrine.aggregation.FlagQueryAggregator
import net.shrine.protocol.UnFlagQueryRequest
import net.shrine.aggregation.UnFlagQueryAggregator
import net.shrine.protocol.ReadResultOutputTypesRequest
import net.shrine.protocol.ReadResultOutputTypesResponse
import net.shrine.protocol.ResultOutputType
/**
* @author clint
* @since Feb 19, 2014
*/
//todo rename? This is the heart of the QEP.
trait AbstractShrineService[BaseResp <: BaseShrineResponse] extends Loggable {
val commonName:String
val auditDao: AuditDao
val authenticator: Authenticator
val authorizationService: QueryAuthorizationService
val includeAggregateResult: Boolean
val broadcastAndAggregationService: BroadcastAndAggregationService
val queryTimeout: Duration
val breakdownTypes: Set[ResultOutputType]
val collectQepAudit:Boolean
protected def doReadResultOutputTypes(request: ReadResultOutputTypesRequest): BaseResp = {
info(s"doReadResultOutputTypes($request)")
afterAuthenticating(request) { authResult =>
val resultOutputTypes = ResultOutputType.nonErrorTypes ++ breakdownTypes
//TODO: XXX: HACK: Would like to remove the cast
ReadResultOutputTypesResponse(resultOutputTypes).asInstanceOf[BaseResp]
}
}
protected def doFlagQuery(request: FlagQueryRequest, shouldBroadcast: Boolean = true): BaseResp = {
doBroadcastQuery(request, new FlagQueryAggregator, shouldBroadcast)
}
protected def doUnFlagQuery(request: UnFlagQueryRequest, shouldBroadcast: Boolean = true): BaseResp = {
doBroadcastQuery(request, new UnFlagQueryAggregator, shouldBroadcast)
}
protected def doRunQuery(request: RunQueryRequest, shouldBroadcast: Boolean): BaseResp = {
info(s"doRunQuery($request,$shouldBroadcast) with $runQueryAggregatorFor")
val result = doBroadcastQuery(request, runQueryAggregatorFor(request), shouldBroadcast)
debug(s"collectQepAudit is $collectQepAudit")
// tuck the ACT audit metrics data into a database here
//todo network id is -1 !
if (collectQepAudit) QepAuditDb.db.insertQepQuery(request,commonName)
result
}
protected def doReadQueryDefinition(request: ReadQueryDefinitionRequest, shouldBroadcast: Boolean): BaseResp = {
doBroadcastQuery(request, new ReadQueryDefinitionAggregator, shouldBroadcast)
}
protected def doReadPdo(request: ReadPdoRequest, shouldBroadcast: Boolean): BaseResp = {
doBroadcastQuery(request, new ReadPdoResponseAggregator, shouldBroadcast)
}
protected def doReadInstanceResults(request: ReadInstanceResultsRequest, shouldBroadcast: Boolean): BaseResp = {
doBroadcastQuery(request, new ReadInstanceResultsAggregator(request.shrineNetworkQueryId, false), shouldBroadcast)
}
protected def doReadQueryInstances(request: ReadQueryInstancesRequest, shouldBroadcast: Boolean): BaseResp = {
info(s"doReadQueryInstances($request)")
afterAuthenticating(request) { authResult =>
val now = XmlDateHelper.now
val networkQueryId = request.queryId
val username = request.authn.username
val groupId = request.projectId
//NB: Return a dummy response, with a dummy QueryInstance containing the network (Shrine) id of the query we'd like
//to get "instances" for. This allows the legacy web client to formulate a request for query results that Shrine
//can understand, while meeting the conversational requirements of the legacy web client.
val instance = QueryInstance(networkQueryId.toString, networkQueryId.toString, username, groupId, now, now)
//TODO: XXX: HACK: Would like to remove the cast
//NB: Munge in username from authentication result
ReadQueryInstancesResponse(networkQueryId, authResult.username, groupId, Seq(instance)).asInstanceOf[BaseResp]
}
}
protected def doReadPreviousQueries(request: ReadPreviousQueriesRequest, shouldBroadcast: Boolean): BaseResp = {
doBroadcastQuery(request, new ReadPreviousQueriesAggregator, shouldBroadcast)
}
protected def doRenameQuery(request: RenameQueryRequest, shouldBroadcast: Boolean): BaseResp = {
doBroadcastQuery(request, new RenameQueryAggregator, shouldBroadcast)
}
protected def doDeleteQuery(request: DeleteQueryRequest, shouldBroadcast: Boolean): BaseResp = {
doBroadcastQuery(request, new DeleteQueryAggregator, shouldBroadcast)
}
protected def doReadApprovedQueryTopics(request: ReadApprovedQueryTopicsRequest, shouldBroadcast: Boolean): BaseResp = afterAuthenticating(request) { _ =>
info(s"doReadApprovedQueryTopics($request)")
//TODO: Is authenticating necessary?
//TODO: XXX: HACK: Would like to remove the cast
authorizationService.readApprovedEntries(request) match {
case Left(errorResponse) => errorResponse.asInstanceOf[BaseResp]
case Right(validResponse) => validResponse.asInstanceOf[BaseResp]
}
}
import broadcastAndAggregationService.sendAndAggregate
protected def doBroadcastQuery(request: BaseShrineRequest, aggregator: Aggregator, shouldBroadcast: Boolean): BaseResp = {
info(s"doBroadcastQuery($request)")
//TODO: XXX: HACK: Would like to remove the cast
def doSynchronousQuery(networkAuthn: AuthenticationInfo) = waitFor(sendAndAggregate(networkAuthn, request, aggregator, shouldBroadcast)).asInstanceOf[BaseResp]
afterAuthenticating(request) { authResult =>
debug(s"doBroadcastQuery($request) authResult is $authResult")
//NB: Use credentials obtained from Authenticator (oddly, we authenticate with one set of credentials and are "logged in" under (possibly!) another
//When making BroadcastMessages
val networkAuthn = AuthenticationInfo(authResult.domain, authResult.username, Credential("", isToken = false))
//NB: Only audit RunQueryRequests
request match {
case runQueryRequest: RunQueryRequest =>
afterAuditingAndAuthorizing(runQueryRequest) (doSynchronousQuery(networkAuthn))
case _ => doSynchronousQuery(networkAuthn)
}
}
}
private[service] val runQueryAggregatorFor: RunQueryRequest => RunQueryAggregator = Aggregators.forRunQueryRequest(includeAggregateResult)
protected def waitFor[R](futureResponse: Future[R]): R = {
XmlDateHelper.time("Waiting for aggregated results")(debug(_)) {
Await.result(futureResponse, queryTimeout)
}
}
private[service] def afterAuditingAndAuthorizing[T](request: RunQueryRequest)(body: => T): T = {
auditTransactionally(request) {
debug(s"afterAuditingAndAuthorizing($request) with $authorizationService")
authorizationService.authorizeRunQueryRequest(request) match {
case na: NotAuthorized => throw na.toException
case _ => ()
}
body
}
}
private[service] def auditTransactionally[T](request: RunQueryRequest)(body: => T): T = {
try { body } finally {
auditDao.addAuditEntry(
request.projectId,
request.authn.domain,
request.authn.username,
request.queryDefinition.toI2b2String, //TODO: Use i2b2 format Still?
request.topicId)
}
}
import AuthenticationResult._
private[service] def afterAuthenticating[T](request: BaseShrineRequest)(f: Authenticated => T): T = {
val AuthenticationInfo(domain, username, _) = request.authn
val authResult = authenticator.authenticate(request.authn)
authResult match {
case a: Authenticated => f(a)
case NotAuthenticated(_, _, reason) => throw new NotAuthenticatedException(s"User $domain:$username could not be authenticated: $reason")
}
}
}
\ No newline at end of file
diff --git a/qep/service/src/main/scala/net/shrine/service/ShrineResource.scala b/qep/service/src/main/scala/net/shrine/service/ShrineResource.scala
index 3a9970b06..111b4f082 100644
--- a/qep/service/src/main/scala/net/shrine/service/ShrineResource.scala
+++ b/qep/service/src/main/scala/net/shrine/service/ShrineResource.scala
@@ -1,258 +1,259 @@
package net.shrine.service
import javax.ws.rs.Consumes
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HeaderParam
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.PathParam
import javax.ws.rs.Produces
import javax.ws.rs.QueryParam
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
import net.shrine.log.Loggable
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.protocol.OutputTypeSet
import net.shrine.protocol.ReadApprovedQueryTopicsRequest
import net.shrine.protocol.ReadInstanceResultsRequest
import net.shrine.protocol.ReadPdoRequest
import net.shrine.protocol.ReadPreviousQueriesRequest
import net.shrine.protocol.ReadQueryDefinitionRequest
import net.shrine.protocol.ReadQueryInstancesRequest
import net.shrine.protocol.ReadQueryResultRequest
import net.shrine.protocol.RenameQueryRequest
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.ShrineRequestHandler
-import net.shrine.protocol.ShrineResponse
import net.shrine.protocol.query.QueryDefinition
import scala.xml.XML
import net.shrine.protocol.BaseShrineResponse
import net.shrine.protocol.ReadTranslatedQueryDefinitionRequest
import net.shrine.protocol.FlagQueryRequest
import net.shrine.protocol.UnFlagQueryRequest
/**
* @author Bill Simons
* @author Clint Gilbert
- * @date 8/30/11
- * @link http://cbmi.med.harvard.edu
- * @link http://chip.org
+ * @since 8/30/11
+ * @see http://cbmi.med.harvard.edu
+ * @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
- * @link http://www.gnu.org/licenses/lgpl.html
+ * @see http://www.gnu.org/licenses/lgpl.html
*/
@Path("/shrine")
@Produces(Array(MediaType.APPLICATION_XML)) //NB: Is a case class to get apply on the companion object, for smoother testing
final case class ShrineResource(shrineRequestHandler: ShrineRequestHandler) extends Loggable {
import ShrineResource.waitTime
@Consumes(Array(MediaType.TEXT_PLAIN))
@POST
@Path("/queries/{queryId}/flag")
def flagQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") networkQueryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean,
flagMessage: String): String = {
val flagMessageOption = Option(flagMessage).filter(!_.trim.isEmpty)
//TODO: What should we return, if anything?
performAndSerialize(_.flagQuery(FlagQueryRequest(projectId, waitTime, authorization, networkQueryId, flagMessageOption), shouldBroadcast))
}
@POST
@Path("/queries/{queryId}/unflag")
def unFlagQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") networkQueryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
//TODO: What should we return, if anything?
performAndSerialize(_.unFlagQuery(UnFlagQueryRequest(projectId, waitTime, authorization, networkQueryId), shouldBroadcast))
}
@GET
@Path("{userId}/approved-topics")
def readApprovedQueryTopics(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("userId") userId: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readApprovedQueryTopics(ReadApprovedQueryTopicsRequest(projectId, waitTime, authorization, userId), shouldBroadcast))
}
@GET
@Path("{userId}/queries")
def readPreviousQueries(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("userId") userId: String,
@QueryParam("fetchSize") fetchSize: Int,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): Response = {
if (userId != authorization.username) {
Response.status(403).build
} else {
val fSize = if (fetchSize != 0) fetchSize else 20
Response.ok.entity {
performAndSerialize(_.readPreviousQueries(ReadPreviousQueriesRequest(projectId, waitTime, authorization, userId, fSize), shouldBroadcast))
}.build
}
}
@POST
@Path("/queries")
@Consumes(Array(MediaType.APPLICATION_XML))
def runQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@HeaderParam("topicId") topicId: String,
+ @HeaderParam("topicName") topicName: String,
//outputTypes will be constructed by JAXRS using the String value of the 'outputTypes' header
@HeaderParam("outputTypes") outputTypes: OutputTypeSet,
queryDefinitionXml: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
val queryDef = QueryDefinition.fromXml(queryDefinitionXml).get
val topicIdOption = Option(topicId).filter(!_.trim.isEmpty)
+ val topicNameOption = Option(topicName).filter(!_.trim.isEmpty)
debug(s"runQuery() with $shrineRequestHandler and $queryDef")
//NB: Create the RunQueryRequest with a dummy networkQueryId of '-1';
//this will be filled in with an appropriately-generated value by the ShrineRequestHandler
- performAndSerialize(_.runQuery(RunQueryRequest(projectId, waitTime, authorization, -1, topicIdOption, outputTypes.toSet, queryDef), shouldBroadcast))
+ performAndSerialize(_.runQuery(RunQueryRequest(projectId, waitTime, authorization, -1, topicIdOption, topicNameOption, outputTypes.toSet, queryDef), shouldBroadcast))
}
@GET
@Path("/queries/{queryId}/instances")
def readQueryInstances(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readQueryInstances(ReadQueryInstancesRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@GET
@Path("/instances/{instanceId}/results")
def readInstanceResults(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("instanceId") instanceId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readInstanceResults(ReadInstanceResultsRequest(projectId, waitTime, authorization, instanceId), shouldBroadcast))
}
@POST //This must be POST, since we're sending content in the request body
@Path("/patient-set/{patientSetCollId}")
@Consumes(Array(MediaType.APPLICATION_XML))
def readPdo(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("patientSetCollId") patientSetCollId: String,
optionsXml: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
import XML.loadString
performAndSerialize(_.readPdo(ReadPdoRequest(projectId, waitTime, authorization, patientSetCollId, loadString(optionsXml)), shouldBroadcast))
}
@GET
@Path("/queries/{queryId}")
def readQueryDefinition(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readQueryDefinition(ReadQueryDefinitionRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@DELETE
@Path("/queries/{queryId}")
def deleteQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.deleteQuery(DeleteQueryRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@POST
@Path("/queries/{queryId}/name")
@Consumes(Array(MediaType.TEXT_PLAIN))
def renameQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
queryName: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.renameQuery(RenameQueryRequest(projectId, waitTime, authorization, queryId, queryName), shouldBroadcast))
}
@GET
@Path("/queries/{queryId}/results")
@Consumes(Array(MediaType.TEXT_PLAIN))
def readQueryResults(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readQueryResult(ReadQueryResultRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@POST
@Path("/queries/translated")
@Consumes(Array(MediaType.APPLICATION_XML))
def readTranslatedQueryDefinition(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean,
queryDefinitionXml: String): String = {
val queryDef = QueryDefinition.fromXml(queryDefinitionXml).get
//NB: Create the RunQueryRequest with a dummy networkQueryId of '-1';
//this will be filled in with an appropriately-generated value by the ShrineRequestHandler
performAndSerialize(_.readTranslatedQueryDefinition(ReadTranslatedQueryDefinitionRequest(authorization, waitTime, queryDef), shouldBroadcast))
}
private def performAndSerialize[R <: BaseShrineResponse](op: ShrineRequestHandler => R): String = {
op(shrineRequestHandler).toXmlString
}
}
//NB: extends ShrineRequestHandler => ShrineResource for smoother testing syntax
object ShrineResource extends (ShrineRequestHandler => ShrineResource) {
import scala.concurrent.duration._
val waitTime = 10.seconds
}
diff --git a/qep/service/src/test/scala/net/shrine/service/ShrineResourceTest.scala b/qep/service/src/test/scala/net/shrine/service/ShrineResourceTest.scala
index 7f9d45bb4..fa073f637 100644
--- a/qep/service/src/test/scala/net/shrine/service/ShrineResourceTest.scala
+++ b/qep/service/src/test/scala/net/shrine/service/ShrineResourceTest.scala
@@ -1,233 +1,234 @@
package net.shrine.service
import net.shrine.util.ShouldMatchersForJUnit
import org.scalatest.mock.EasyMockSugar
import org.easymock.EasyMock.{ eq => isEqualTo, expect => invoke, reportMatcher }
import net.shrine.protocol._
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import org.easymock.IArgumentMatcher
import org.easymock.internal.ArgumentToString
import org.junit.Test
import net.shrine.util.XmlDateHelper
import org.junit.Before
/**
* @author Clint Gilbert
- * @date 9/13/2011
- * @link http://cbmi.med.harvard.edu
- * @link http://chip.org
+ * @since 9/13/2011
+ * @see http://cbmi.med.harvard.edu
+ * @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
- * @link http://www.gnu.org/licenses/lgpl.html
+ * @see http://www.gnu.org/licenses/lgpl.html
*/
final class ShrineResourceTest extends ShouldMatchersForJUnit with EasyMockSugar {
private var handler: ShrineRequestHandler = _
private var resource: ShrineResource = _
private val projectId = "projectId"
private val authenticationInfo = new AuthenticationInfo("domain", "username", new Credential("secret", true))
private val userId = "userId"
private val shouldBroadcast = true
@Before
def setUp(): Unit = {
handler = mock[ShrineRequestHandler]
resource = new ShrineResource(handler)
}
import ShrineResource.waitTime
@Test
def testReadApprovedQueryTopics {
val expectedRequest = ReadApprovedQueryTopicsRequest(projectId, waitTime, authenticationInfo, userId)
val expectedResponse = ReadApprovedQueryTopicsResponse(Seq(ApprovedTopic(123L, "foo")))
setExpectations(_.readApprovedQueryTopics, expectedRequest, expectedResponse)
execute {
resource.readApprovedQueryTopics(projectId, authenticationInfo, userId, shouldBroadcast)
}
}
@Test
def testReadPreviousQueries {
def doTestReadPreviousQueries(userId: String, fetchSize: Int, expectedFetchSize: Int) {
//Call setUp again create a new mock and new ShrinResource;
//each pair of expecting/whenExecuting calls needs a fresh mock.
this.setUp()
val expectedRequest = ReadPreviousQueriesRequest(projectId, waitTime, authenticationInfo, userId, expectedFetchSize)
val expectedResponse = ReadPreviousQueriesResponse(Seq.empty)
setExpectations(_.readPreviousQueries, expectedRequest, expectedResponse)
execute {
resource.readPreviousQueries(projectId, authenticationInfo, userId, fetchSize, shouldBroadcast)
}
}
doTestReadPreviousQueries(authenticationInfo.username, -100, -100)
doTestReadPreviousQueries(authenticationInfo.username, 0, 20)
doTestReadPreviousQueries(authenticationInfo.username, 1, 1)
doTestReadPreviousQueries(authenticationInfo.username, 100, 100)
}
@Test
def testRunQuery {
val outputTypes = ResultOutputType.values.toSet
val queryDef = QueryDefinition("foo", Term("nuh"))
val topicId = Some("topicId")
+ val topicName = Some("topicName")
- val expectedRequest = RunQueryRequest(projectId, waitTime, authenticationInfo, 999L, topicId, outputTypes, queryDef)
+ val expectedRequest = RunQueryRequest(projectId, waitTime, authenticationInfo, 999L, topicId, topicName, outputTypes, queryDef)
val expectedResponse = RunQueryResponse(999L, null, "userId", "groupId", queryDef, 0L, QueryResult(1L, 0L, Some(ResultOutputType.PATIENT_COUNT_XML), 123L, None, None, None, QueryResult.StatusType.Finished, None, Map.empty))
def isEqualToExceptForQueryId(expected: RunQueryRequest): RunQueryRequest = {
reportMatcher(new IArgumentMatcher {
override def matches(argument: AnyRef): Boolean = {
argument.isInstanceOf[RunQueryRequest] && {
val actual = argument.asInstanceOf[RunQueryRequest]
//Everything *but* queryId, which is randomly generated by ShrineResource :\
actual.authn == expected.authn &&
actual.outputTypes == expected.outputTypes &&
actual.projectId == expected.projectId &&
actual.queryDefinition == expected.queryDefinition &&
actual.requestType == expected.requestType &&
actual.topicId == expected.topicId &&
actual.waitTime == expected.waitTime
}
}
override def appendTo(buffer: StringBuffer): Unit = ArgumentToString.appendArgument(expected, buffer)
})
null
}
expecting {
invoke(handler.runQuery(isEqualToExceptForQueryId(expectedRequest), isEqualTo(shouldBroadcast))).andReturn(expectedResponse)
}
execute {
- resource.runQuery(projectId, authenticationInfo, topicId.get, new OutputTypeSet(outputTypes), queryDef.toXmlString, shouldBroadcast)
+ resource.runQuery(projectId, authenticationInfo, topicId.get, topicName.get, new OutputTypeSet(outputTypes), queryDef.toXmlString, shouldBroadcast)
}
}
@Test
def testReadQueryInstances {
val queryId = 999L
val expectedRequest = ReadQueryInstancesRequest(projectId, waitTime, authenticationInfo, queryId)
val expectedResponse = ReadQueryInstancesResponse(queryId, "userId", "groupId", Seq.empty)
setExpectations(_.readQueryInstances, expectedRequest, expectedResponse)
execute {
resource.readQueryInstances(projectId, authenticationInfo, queryId, shouldBroadcast)
}
}
@Test
def testReadInstanceResults {
val instanceId = 123456789L
val expectedRequest = ReadInstanceResultsRequest(projectId, waitTime, authenticationInfo, instanceId)
val expectedResponse = AggregatedReadInstanceResultsResponse(instanceId, Seq.empty)
setExpectations(_.readInstanceResults, expectedRequest, expectedResponse)
execute {
resource.readInstanceResults(projectId, authenticationInfo, instanceId, shouldBroadcast)
}
}
@Test
def testReadPdo {
val patientSetCollId = "123456789L"
val optionsXml =
def paramResponse = ParamResponse("foo", "bar", "baz")
val expectedRequest = ReadPdoRequest(projectId, waitTime, authenticationInfo, patientSetCollId, optionsXml)
val expectedResponse = ReadPdoResponse(Seq(EventResponse("event", "patient", None, None, Seq.empty)), Seq(PatientResponse("patientId", Seq(paramResponse))),
Seq(ObservationResponse(None, "eventId", None, "patientId", None, None, None, "observerCode", "startDate", None, "valueTypeCode",None,None,None,None,None,None,None, Seq(paramResponse))))
setExpectations(_.readPdo, expectedRequest, expectedResponse)
execute {
resource.readPdo(projectId, authenticationInfo, patientSetCollId, optionsXml.toString, shouldBroadcast)
}
}
@Test
def testReadQueryDefinition {
val queryId = 123456789L
val expectedRequest = ReadQueryDefinitionRequest(projectId, waitTime, authenticationInfo, queryId)
val expectedResponse = ReadQueryDefinitionResponse(queryId, "name", "userId", XmlDateHelper.now, "")
setExpectations(_.readQueryDefinition, expectedRequest, expectedResponse)
execute {
resource.readQueryDefinition(projectId, authenticationInfo, queryId, shouldBroadcast)
}
}
@Test
def testDeleteQuery {
val queryId = 123456789L
val expectedRequest = DeleteQueryRequest(projectId, waitTime, authenticationInfo, queryId)
val expectedResponse = DeleteQueryResponse(queryId)
setExpectations(_.deleteQuery, expectedRequest, expectedResponse)
execute {
resource.deleteQuery(projectId, authenticationInfo, queryId, shouldBroadcast)
}
}
@Test
def testRenameQuery {
val queryId = 123456789L
val queryName = "asjkdhkahsf"
val expectedRequest = RenameQueryRequest(projectId, waitTime, authenticationInfo, queryId, queryName)
val expectedResponse = RenameQueryResponse(queryId, queryName)
setExpectations(_.renameQuery, expectedRequest, expectedResponse)
execute {
resource.renameQuery(projectId, authenticationInfo, queryId, queryName, shouldBroadcast)
}
}
def testReadQueryResult {
val queryId = 123456789L
val expectedRequest = ReadQueryResultRequest(projectId, waitTime, authenticationInfo, queryId)
val expectedResponse = AggregatedReadQueryResultResponse(queryId, Seq.empty)
setExpectations(_.readQueryResult, expectedRequest, expectedResponse)
execute {
resource.readQueryResults(projectId, authenticationInfo, queryId, shouldBroadcast)
}
}
private def execute(f: => Unit) = whenExecuting(handler)(f)
private def setExpectations[Req <: BaseShrineRequest, Resp <: BaseShrineResponse](handlerMethod: ShrineRequestHandler => (Req, Boolean) => BaseShrineResponse, expectedRequest: Req, expectedResponse: Resp) {
expecting {
invoke(handlerMethod(handler)(isEqualTo(expectedRequest), isEqualTo(shouldBroadcast))).andReturn(expectedResponse)
}
}
}
\ No newline at end of file
diff --git a/qep/service/src/test/scala/net/shrine/service/ShrineServiceTest.scala b/qep/service/src/test/scala/net/shrine/service/ShrineServiceTest.scala
index 9bdc609b4..4f48a105a 100644
--- a/qep/service/src/test/scala/net/shrine/service/ShrineServiceTest.scala
+++ b/qep/service/src/test/scala/net/shrine/service/ShrineServiceTest.scala
@@ -1,201 +1,201 @@
package net.shrine.service
import org.junit.Test
import org.scalatest.mock.EasyMockSugar
import net.shrine.authorization.QueryAuthorizationService
import net.shrine.service.dao.AbstractAuditDaoTest
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.Credential
import net.shrine.protocol.ReadApprovedQueryTopicsRequest
import net.shrine.protocol.ReadApprovedQueryTopicsResponse
import net.shrine.protocol.ReadQueryInstancesRequest
import net.shrine.protocol.ReadQueryInstancesResponse
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.query.QueryDefinition
import net.shrine.protocol.query.Term
import net.shrine.authorization.AuthorizationResult
import net.shrine.authentication.Authenticator
import net.shrine.authentication.AuthenticationResult
import net.shrine.authentication.NotAuthenticatedException
import net.shrine.protocol.ErrorResponse
/**
* @author Bill Simons
* @author Clint Gilbert
* @since 3/30/11
* @see http://cbmi.med.harvard.edu
* @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @see http://www.gnu.org/licenses/lgpl.html
*/
final class ShrineServiceTest extends AbstractAuditDaoTest with EasyMockSugar {
import scala.concurrent.duration._
@Test
def testReadQueryInstances {
val projectId = "foo"
val queryId = 123L
val authn = AuthenticationInfo("some-domain", "some-username", Credential("blarg", false))
val req = ReadQueryInstancesRequest(projectId, 1.millisecond, authn, queryId)
val service = ShrineService("example.com",null, AllowsAllAuthenticator, null, true, null, null, Set.empty,false)
val response = service.readQueryInstances(req).asInstanceOf[ReadQueryInstancesResponse]
response should not be (null)
response.groupId should equal(projectId)
response.queryMasterId should equal(queryId)
response.userId should equal(authn.username)
val Seq(instance) = response.queryInstances
instance.startDate should not be (null)
instance.endDate should not be (null)
instance.startDate should equal(instance.endDate)
instance.groupId should equal(projectId)
instance.queryInstanceId should equal(queryId.toString)
instance.queryMasterId should equal(queryId.toString)
instance.userId should equal(authn.username)
}
private val authn = AuthenticationInfo("some-domain", "some-user", Credential("some-password", false))
private val projectId = "projectId"
private val queryDef = QueryDefinition("yo", Term("foo"))
- private val request = RunQueryRequest(projectId, 1.millisecond, authn, 0L, Some("topicId"), Set.empty, queryDef)
+ private val request = RunQueryRequest(projectId, 1.millisecond, authn, 0L, Some("topicId"), Some("Topic Name"), Set.empty, queryDef)
@Test
def testRunQueryAggregatorFor {
def doTestRunQueryAggregatorFor(addAggregatedResult: Boolean) {
val service = ShrineService("example.com",null, null, null, addAggregatedResult, null, null, Set.empty,false)
val aggregator = service.runQueryAggregatorFor(request)
aggregator should not be (null)
aggregator.queryId should be(-1L)
aggregator.groupId should be(projectId)
aggregator.userId should be(authn.username)
aggregator.requestQueryDefinition should be(queryDef)
aggregator.addAggregatedResult should be(addAggregatedResult)
}
doTestRunQueryAggregatorFor(true)
doTestRunQueryAggregatorFor(false)
}
@Test
def testAuditTransactionally = afterMakingTables {
def doTestAuditTransactionally(shouldThrow: Boolean) {
val service = ShrineService("example.com",auditDao, null, null, true, null, null, Set.empty,false)
if (shouldThrow) {
intercept[Exception] {
service.auditTransactionally(request)(throw new Exception)
}
} else {
val x = 1
val actual = service.auditTransactionally(request)(x)
actual should be(x)
}
//We should have recorded an audit entry no matter what
val Seq(entry) = auditDao.findRecentEntries(1)
entry.domain should be(authn.domain)
entry.username should be(authn.username)
entry.project should be(projectId)
entry.queryText should be(Some(queryDef.toI2b2String))
entry.queryTopic should be(request.topicId)
entry.time should not be (null)
}
doTestAuditTransactionally(false)
doTestAuditTransactionally(true)
}
import ShrineServiceTest._
@Test
def testAfterAuthenticating {
def doTestAfterAuthenticating(shouldAuthenticate: Boolean) {
val service = ShrineService("example.com",auditDao, new MockAuthenticator(shouldAuthenticate), new MockAuthService(true), true, null, null, Set.empty,false)
if (shouldAuthenticate) {
var foo = false
service.afterAuthenticating(request) { _ =>
foo = true
}
foo should be(true)
} else {
intercept[NotAuthenticatedException] {
service.afterAuthenticating(request) { _ => () }
}
}
}
doTestAfterAuthenticating(true)
doTestAfterAuthenticating(false)
}
@Test
def testAfterAuditingAndAuthorizing = afterMakingTables {
def doAfterAuditingAndAuthorizing(shouldBeAuthorized: Boolean, shouldThrow: Boolean) {
val service = ShrineService("example.com",auditDao, AllowsAllAuthenticator, new MockAuthService(shouldBeAuthorized), true, null, null, Set.empty,false)
if (shouldThrow || !shouldBeAuthorized) {
intercept[Exception] {
service.afterAuditingAndAuthorizing(request)(throw new Exception)
}
} else {
val x = 1
val actual = service.afterAuditingAndAuthorizing(request)(x)
actual should be(x)
}
//We should have recorded an audit entry no matter what
val Seq(entry) = auditDao.findRecentEntries(1)
entry.domain should be(authn.domain)
entry.username should be(authn.username)
entry.project should be(projectId)
entry.queryText should be(Some(queryDef.toI2b2String))
entry.queryTopic should be(request.topicId)
entry.time should not be (null)
}
doAfterAuditingAndAuthorizing(true, true)
doAfterAuditingAndAuthorizing(true, false)
doAfterAuditingAndAuthorizing(false, true)
doAfterAuditingAndAuthorizing(false, false)
}
}
object ShrineServiceTest {
final class MockAuthenticator(shouldAuthenticate: Boolean) extends Authenticator {
override def authenticate(authn: AuthenticationInfo): AuthenticationResult = {
if (shouldAuthenticate) { AuthenticationResult.Authenticated(authn.domain, authn.username) }
else { AuthenticationResult.NotAuthenticated(authn.domain, authn.username, "blarg") }
}
}
final class MockAuthService(shouldWork: Boolean) extends QueryAuthorizationService {
def authorizeRunQueryRequest(request: RunQueryRequest): AuthorizationResult = {
if (shouldWork) { AuthorizationResult.Authorized }
else { AuthorizationResult.NotAuthorized("blarg") }
}
def readApprovedEntries(request: ReadApprovedQueryTopicsRequest): Either[ErrorResponse, ReadApprovedQueryTopicsResponse] = ???
}
}
\ No newline at end of file
diff --git a/tools/scanner/src/main/scala/net/shrine/utilities/scanner/BroadcastServiceScannerClient.scala b/tools/scanner/src/main/scala/net/shrine/utilities/scanner/BroadcastServiceScannerClient.scala
index 6b9e0037c..edbaac74b 100644
--- a/tools/scanner/src/main/scala/net/shrine/utilities/scanner/BroadcastServiceScannerClient.scala
+++ b/tools/scanner/src/main/scala/net/shrine/utilities/scanner/BroadcastServiceScannerClient.scala
@@ -1,96 +1,96 @@
package net.shrine.utilities.scanner
import net.shrine.log.Loggable
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import Scanner.QueryDefaults.outputTypes
import Scanner.QueryDefaults.topicId
import ScannerClient.errorTermResult
import ScannerClient.toQueryDef
import net.shrine.aggregation.Aggregators
import net.shrine.aggregation.ReadQueryResultAggregator
import net.shrine.broadcaster.BroadcastAndAggregationService
import net.shrine.protocol.AggregatedReadQueryResultResponse
import net.shrine.protocol.AggregatedRunQueryResponse
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.ReadQueryResultRequest
import net.shrine.protocol.RunQueryRequest
import scala.concurrent.duration.Duration
import net.shrine.authentication.AuthenticationResult
import net.shrine.protocol.Credential
import net.shrine.authentication.Authenticator
import net.shrine.authentication.NotAuthenticatedException
/**
* @author clint
* @date Mar 14, 2013
*/
class BroadcastServiceScannerClient(
val projectId: String,
override val authn: AuthenticationInfo,
val broadcastAndAggregationService: BroadcastAndAggregationService,
override val authenticator: Authenticator,
implicit val executionContext: ExecutionContext) extends ScannerClient with Loggable {
//TODO: Make this configurable
private val waitTime: Duration = {
import scala.concurrent.duration._
10.seconds
}
//Don't ask for an aggregated (summed) result, since we'll get at most one result back in any case
private val runQueryAggregatorSource = Aggregators.forRunQueryRequest(false) _
private def toAuthn(authResult: AuthenticationResult.Authenticated) = AuthenticationInfo(authResult.domain, authResult.username, Credential("", false))
override def query(term: String): Future[TermResult] = afterAuthenticating { authResult =>
import Scanner.QueryDefaults._
info(s"Querying for '$term'")
- val request = RunQueryRequest(projectId, waitTime, authn, -1L, Option(topicId), outputTypes, toQueryDef(term))
+ val request = RunQueryRequest(projectId, waitTime, authn, -1L, Option(topicId), Option(topicName), outputTypes, toQueryDef(term))
val futureResponse = broadcastAndAggregationService.sendAndAggregate(toAuthn(authResult), request, runQueryAggregatorSource(request), false)
def toTermResult(runQueryResponse: AggregatedRunQueryResponse): TermResult = {
val termResultOption = for {
shrineQueryResult <- runQueryResponse.results.headOption
} yield TermResult(runQueryResponse.queryId, shrineQueryResult.resultId, term, shrineQueryResult.statusType, shrineQueryResult.setSize)
//TODO: Is this the right query id to use here?
termResultOption.getOrElse(errorTermResult(runQueryResponse.queryId, term))
}
futureResponse.collect { case resp: AggregatedRunQueryResponse => resp }.map(toTermResult)
}
override def retrieveResults(termResult: TermResult): Future[TermResult] = afterAuthenticating { authResult =>
info(s"Retrieving results for previously-incomplete query for '${termResult.term}'")
val request = ReadQueryResultRequest(projectId, waitTime, authn, termResult.networkQueryId)
val futureResponse = broadcastAndAggregationService.sendAndAggregate(toAuthn(authResult), request, new ReadQueryResultAggregator(termResult.networkQueryId, false), false)
def toTermResult(readQueryResultResponse: AggregatedReadQueryResultResponse): TermResult = {
val termResultOption = for {
shrineQueryResult <- readQueryResultResponse.results.headOption
} yield {
def elapsed = for {
start <- shrineQueryResult.startDate.map(_.toGregorianCalendar.getTimeInMillis)
end <- shrineQueryResult.endDate.map(_.toGregorianCalendar.getTimeInMillis)
} yield end - start
debug(s"CRC Query result: ${ shrineQueryResult.statusType }: (${ elapsed } ms) '${ shrineQueryResult.description.getOrElse("No Description") }', '${ shrineQueryResult.statusMessage.getOrElse("No status message") }'")
termResult.copy(status = shrineQueryResult.statusType, count = shrineQueryResult.setSize)
}
//TODO: Is this the right query id to use here?
termResultOption.getOrElse(errorTermResult(termResult.networkQueryId, termResult.term))
}
futureResponse.collect { case resp: AggregatedReadQueryResultResponse => resp }.map(toTermResult)
}
}
\ No newline at end of file
diff --git a/tools/scanner/src/main/scala/net/shrine/utilities/scanner/Scanner.scala b/tools/scanner/src/main/scala/net/shrine/utilities/scanner/Scanner.scala
index 715cfc189..5b55eb832 100644
--- a/tools/scanner/src/main/scala/net/shrine/utilities/scanner/Scanner.scala
+++ b/tools/scanner/src/main/scala/net/shrine/utilities/scanner/Scanner.scala
@@ -1,161 +1,162 @@
package net.shrine.utilities.scanner
import net.shrine.log.Loggable
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.duration.Duration
import scala.concurrent.duration.DurationInt
import scala.util.control.NonFatal
import net.shrine.config.mappings.AdapterMappingsSource
import net.shrine.ont.data.OntologyDao
import net.shrine.protocol.ResultOutputType
/**
* @author clint
- * @date Mar 5, 2013
+ * @since Mar 5, 2013
*/
final class Scanner(
val maxTimeToWaitForResult: Duration,
val reScanTimeout: Duration,
val adapterMappingsSource: AdapterMappingsSource,
val ontologyDao: OntologyDao,
val client: ScannerClient) extends Loggable {
def scan(): ScanResults = doScan()
protected def doScan(): ScanResults = {
info("Shrine Scanner starting")
val mappedNetworkTerms = adapterMappingsSource.load.get.networkTerms
def allShrineOntologyTerms = ontologyDao.ontologyEntries.map(_.path).toSet
val termsExpectedToBeUnmapped = allShrineOntologyTerms -- mappedNetworkTerms
info(s"We expect ${mappedNetworkTerms.size} to be mapped, and ${termsExpectedToBeUnmapped.size} to be unmapped.")
doScan(mappedNetworkTerms, termsExpectedToBeUnmapped)
}
import scala.concurrent.duration._
private def obtainVia[T](get: T => Future[TermResult]): T => ScanQueryResult = {
input =>
try {
//TODO: Evaluate, possibly don't block?
val result = Await.result(get(input), maxTimeToWaitForResult)
debug(s"Status ${result.status} received, queried for $input")
result
} catch {
case NonFatal(e) => {
warn(s"Error obtaining results for input $input: ", e)
QueryFailure(input, e)
}
}
}
private def obtainResultsAndFailures[T](terms: Iterable[T], queryFor: T => ScanQueryResult): (Iterable[TermResult], Iterable[QueryFailure[T]]) = {
val results = terms.map(queryFor)
(results.collect { case t: TermResult => t }, results.collect { case f: QueryFailure[T] => f })
}
private def doScan(mappedNetworkTerms: Set[String], termsExpectedToBeUnmapped: Set[String]): ScanResults = {
val queryFor = obtainVia(client.query)
val (resultsForMappedTerms, failuresForMappedTerms) = obtainResultsAndFailures(mappedNetworkTerms, queryFor)
val (resultsForUnMappedTerms, failuresForUnMappedTerms) = obtainResultsAndFailures(termsExpectedToBeUnmapped, queryFor)
val (finishedAndShouldHaveBeenMapped, didntFinishAndShouldHaveBeenMapped) = resultsForMappedTerms.partition(_.status.isDone)
val (finishedAndShouldNotHaveBeenMapped, didntFinishAndShouldNotHaveBeenMapped) = resultsForUnMappedTerms.partition(_.status.isDone)
//Terms that we expected to BE mapped, but were NOT mapped
val shouldHaveBeenMapped = finishedAndShouldHaveBeenMapped.filter(_.status.isError)
//Terms that we expected to NOT be mapped, but ARE mapped
val shouldNotHaveBeenMapped = finishedAndShouldNotHaveBeenMapped.filterNot(_.status.isError)
val reScanResults = reScan(didntFinishAndShouldHaveBeenMapped, didntFinishAndShouldNotHaveBeenMapped)
val finalSouldHaveBeenMappedSet = toTermSet(shouldHaveBeenMapped) ++ reScanResults.shouldHaveBeenMapped
val finalSouldNotHaveBeenMappedSet = toTermSet(shouldNotHaveBeenMapped) ++ reScanResults.shouldNotHaveBeenMapped
val failed = toTermSet(failuresForMappedTerms ++ failuresForUnMappedTerms) ++ reScanResults.failed
//Split query results into those that completed on the first try, and those that didn't
ScanResults(finalSouldHaveBeenMappedSet, finalSouldNotHaveBeenMappedSet, reScanResults.neverFinished, failed)
}
private def reScan(neverFinishedShouldHaveBeenMapped: Iterable[TermResult], neverFinishedShouldNotHaveBeenMapped: Iterable[TermResult]): ScanResults = {
if (neverFinishedShouldHaveBeenMapped.isEmpty && neverFinishedShouldNotHaveBeenMapped.isEmpty) { ScanResults.empty }
else {
val total = neverFinishedShouldHaveBeenMapped.size + neverFinishedShouldNotHaveBeenMapped.size
info(s"Sleeping for ${reScanTimeout} before retreiving results for $total incomplete queries...")
Thread.sleep(reScanTimeout.toMillis)
val retrieve = obtainVia(client.retrieveResults)
val (neverFinishedShouldHaveBeenMappedRetries, failedShouldHaveBeenMappedRetries) = obtainResultsAndFailures(neverFinishedShouldHaveBeenMapped, retrieve)
val (neverFinishedShouldNotHaveBeenMappedRetries, failedShouldNotHaveBeenMappedRetries) = obtainResultsAndFailures(neverFinishedShouldNotHaveBeenMapped, retrieve)
val (doneShouldHaveBeenMapped, stillNotFinishedShouldHaveBeenMapped) = neverFinishedShouldHaveBeenMappedRetries.partition(_.status.isDone)
val (doneShouldNotHaveBeenMapped, stillNotFinishedShouldNotHaveBeenMapped) = neverFinishedShouldNotHaveBeenMappedRetries.partition(_.status.isDone)
val shouldHaveBeenMapped = doneShouldHaveBeenMapped.filter(_.status.isError)
val shouldNotHaveBeenMapped = doneShouldNotHaveBeenMapped.filterNot(_.status.isError)
val stillNotFinished = stillNotFinishedShouldHaveBeenMapped ++ stillNotFinishedShouldNotHaveBeenMapped
val failed = failedShouldHaveBeenMappedRetries ++ failedShouldNotHaveBeenMappedRetries
ScanResults(toTermSet(shouldHaveBeenMapped), toTermSet(shouldNotHaveBeenMapped), toTermSet(stillNotFinished), toTermSet(failed))
}
}
private def toTermSet(results: Iterable[TermResult]): Set[String] = results.map(_.term).toSet
import Scanner.Termable
private def toTermSet[T : Termable](results: Iterable[QueryFailure[T]]): Set[String] = results.map(implicitly[Termable[T]].getTerm).toSet
}
object Scanner {
private[scanner] trait Termable[T] {
def getTerm(t: T): String
def getTerm(t: QueryFailure[T]): String
}
private[scanner] object Termable {
implicit val stringIsTermable: Termable[String] = new Termable[String] {
override def getTerm(t: String) = t
override def getTerm(f: QueryFailure[String]) = f.input
}
implicit val termResultIsTermable: Termable[TermResult] = new Termable[TermResult] {
override def getTerm(t: TermResult) = t.term
override def getTerm(f: QueryFailure[TermResult]) = f.input.term
}
}
final object QueryDefaults {
val topicId = "Scanner Util - Unknown Topic ID" //???
+ val topicName = "Scanner Util - Unknown Topic Name"
val outputTypes = Set(ResultOutputType.PATIENT_COUNT_XML)
}
}
\ No newline at end of file