Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Marko Milić 2023-12-06 17:56:43 +01:00
commit aed7aef650
13 changed files with 80 additions and 789 deletions

View File

@ -360,16 +360,6 @@
<artifactId>geocalc</artifactId>
<version>0.5.7</version>
</dependency>
<!-- embeded kafka for unit test start -->
<!-- https://mvnrepository.com/artifact/io.github.embeddedkafka/embedded-kafka -->
<dependency>
<groupId>io.github.embeddedkafka</groupId>
<artifactId>embedded-kafka_2.12</artifactId>
<version>2.4.1.1</version>
<scope>test</scope>
</dependency>
<!-- embeded kafka for unit test end -->
<!-- https://mvnrepository.com/artifact/com.twilio.sdk/twilio -->
<dependency>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio</artifactId>

View File

@ -777,20 +777,6 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
}
}
def basicUrlValidation(urlString: String): Boolean = {
//in scala test - org.scalatest.FeatureSpecLike.scenario:
// redirectUrl = http%3A%2F%2Flocalhost%3A8016%3Foauth_token%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461
// URLDecoder.decode(urlString,"UTF-8")-->http://localhost:8016?oauth_token=EBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK&oauth_verifier=63461
val regex =
"""((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_\/]*)#?(?:[\w]*))?)""".r
val decodeUrlValue = URLDecoder.decode(urlString, "UTF-8").trim()
decodeUrlValue match {
case regex(_*) if (decodeUrlValue.length <= 2048) => true
case _ => false
}
}
/** only A-Z, a-z, 0-9,-,_,. =, & and max length <= 2048 */
def basicUriAndQueryStringValidation(urlString: String): Boolean = {
val regex =

View File

@ -3056,7 +3056,7 @@ object NewStyle extends MdcLoggable{
private[this] val endpointMappingTTL = APIUtil.getPropsValue(s"endpointMapping.cache.ttl.seconds", "0").toInt
def getEndpointMappings(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[EndpointMappingT]] = {
def getEndpointMappings(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[EndpointMappingT]] = Future{
import scala.concurrent.duration._
validateBankId(bankId, callContext)
@ -3064,7 +3064,7 @@ object NewStyle extends MdcLoggable{
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
CacheKeyFromArguments.buildCacheKey {
Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(endpointMappingTTL second) {
Future{(EndpointMappingProvider.endpointMappingProvider.vend.getAllEndpointMappings(bankId), callContext)}
{(EndpointMappingProvider.endpointMappingProvider.vend.getAllEndpointMappings(bankId), callContext)}
}
}
}

View File

@ -1427,19 +1427,22 @@ trait APIMethods510 {
"GET",
"/management/metrics",
"Get Metrics",
s"""Get the all metrics
s"""Get API metrics rows. These are records of each REST API call.
|
|require CanReadMetrics role
|
|Filters Part 1.*filtering* (no wilde cards etc.) parameters to GET /management/metrics
|
|Should be able to filter on the following metrics fields
|You can filter by the following fields by applying url parameters
|
|eg: /management/metrics?from_date=$DateWithMsExampleString&to_date=$DateWithMsExampleString&limit=50&offset=2
|
|1 from_date (defaults to one week before current date): eg:from_date=$DateWithMsExampleString
|1 from_date e.g.:from_date=$DateWithMsExampleString Defaults to the Unix Epoch i.e. ${theEpochTime}
|
|2 to_date (defaults to current date) eg:to_date=$DateWithMsExampleString
|2 to_date e.g.:to_date=$DateWithMsExampleString Defaults to a far future date i.e. ${APIUtil.ToDateInFuture}
|
|Note: it is recommended you send a valid from_date (e.g. 5 seconds ago) and to_date (now + 1 second) if you want to get the latest records
| Otherwise you may receive stale cached results.
|
|3 limit (for pagination: defaults to 50) eg:limit=200
|

View File

@ -360,7 +360,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
}
// TODO Cache this as long as fromDate and toDate are in the past (before now)
override def getTopApisFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopApi]]] = {
override def getTopApisFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopApi]]] = Future{
/**
* Please note that "var cacheKey = (randomUUID().toString, randomUUID().toString, randomUU
* is just a temporary value field with UUID values in order to prevent any ambiguity.
@ -369,7 +369,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
*/
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
CacheKeyFromArguments.buildCacheKey {Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(cachedTopApis seconds){
Future{
{
val fromDate = queryParams.collect { case OBPFromDate(value) => value }.headOption
val toDate = queryParams.collect { case OBPToDate(value) => value }.headOption
val consumerId = queryParams.collect { case OBPConsumerId(value) => value }.headOption.flatMap(consumerIdToPrimaryKey)
@ -440,7 +440,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
}}
// TODO Cache this as long as fromDate and toDate are in the past (before now)
override def getTopConsumersFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopConsumer]]] = {
override def getTopConsumersFuture(queryParams: List[OBPQueryParam]): Future[Box[List[TopConsumer]]] = Future {
/**
* Please note that "var cacheKey = (randomUUID().toString, randomUUID().toString, randomUU
* is just a temporary value field with UUID values in order to prevent any ambiguity.
@ -449,7 +449,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
*/
var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString)
CacheKeyFromArguments.buildCacheKey {Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(cachedTopConsumers seconds){
Future {
val fromDate = queryParams.collect { case OBPFromDate(value) => value }.headOption
val toDate = queryParams.collect { case OBPToDate(value) => value }.headOption
val consumerId = queryParams.collect { case OBPConsumerId(value) => value }.headOption.flatMap(consumerIdToPrimaryKey)
@ -519,7 +519,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
}
tryo(result)
}
}}}
}}
}

View File

@ -48,8 +48,10 @@ class OAuthWorkedThanks extends MdcLoggable {
val redirectUrl = ObpS.param("redirectUrl").map(urlDecode(_))
logger.debug(s"OAuthWorkedThanks.thanks.redirectUrl $redirectUrl")
//extract the clean(omit the parameters) redirect url from request url
val requestedRedirectURL = Helper.extractCleanRedirectURL(redirectUrl.openOr("invalidRequestedRedirectURL")) openOr("invalidRequestedRedirectURL")
logger.debug(s"OAuthWorkedThanks.thanks.requestedRedirectURL $requestedRedirectURL")
val staticPortionOfRedirectUrl = Helper.getStaticPortionOfRedirectURL(redirectUrl.openOr("invalidRequestedRedirectURL")) openOr("invalidRequestedRedirectURL")
val hostOnlyOfRedirectUrlLegacy = Helper.getHostOnlyOfRedirectURL(staticPortionOfRedirectUrl) openOr("invalidRequestedRedirectURL")
logger.debug(s"OAuthWorkedThanks.thanks.staticPortionOfRedirectUrl $staticPortionOfRedirectUrl")
logger.debug(s"OAuthWorkedThanks.thanks.hostOnlyOfRedirectUrlLegacy $hostOnlyOfRedirectUrlLegacy")
val requestedOauthToken = Helper.extractOauthToken(redirectUrl.openOr("No Oauth Token here")) openOr("No Oauth Token here")
logger.debug(s"OAuthWorkedThanks.thanks.requestedOauthToken $requestedOauthToken")
@ -62,13 +64,10 @@ class OAuthWorkedThanks extends MdcLoggable {
redirectUrl match {
case Full(url) =>
//this redirect url is checked by following, no open redirect issue.
// TODO maybe handle case of extra trailing / on the url ?
val incorrectRedirectUrlMessage = s"The validRedirectURL is $validRedirectURL but the staticPortionOfRedirectUrl was $staticPortionOfRedirectUrl"
val incorrectRedirectUrlMessage = s"The validRedirectURL is $validRedirectURL but the requestedRedirectURL was $requestedRedirectURL"
if(validRedirectURL.equals(requestedRedirectURL)) {
//hostOnlyOfRedirectUrlLegacy is deprecated now, we use the staticPortionOfRedirectUrl stead,
if(validRedirectURL.equals(staticPortionOfRedirectUrl)|| validRedirectURL.equals(hostOnlyOfRedirectUrlLegacy)) {
"#redirect-link [href]" #> url &
".app-name"#> appName //there may be several places to be modified in html, so here use the class, not the id.
}else{

View File

@ -1,9 +1,8 @@
package code.util
import java.net.{Socket, SocketException}
import java.net.{Socket, SocketException, URL}
import java.util.UUID.randomUUID
import java.util.{Date, GregorianCalendar}
import code.api.util.{APIUtil, CallContext, CallContextLight, CustomJsonFormats}
import code.api.{APIFailureNewStyle, Constant}
import code.api.util.APIUtil.fullBoxOrException
@ -20,7 +19,9 @@ import com.openbankproject.commons.util.{ReflectUtils, RequiredFieldValidation,
import com.tesobe.CacheKeyFromArguments
import net.liftweb.http.S
import net.liftweb.util.Helpers
import net.liftweb.util.Helpers.tryo
import net.sf.cglib.proxy.{Enhancer, MethodInterceptor, MethodProxy}
import java.lang.reflect.Method
import scala.concurrent.Future
import scala.util.Random
@ -167,8 +168,30 @@ object Helper extends Loggable {
prettyRender(decompose(input))
}
def extractCleanRedirectURL(input: String): Box[String] = {
Full(input.split("\\?oauth_token=")(0))
/**
*
* @param redirectUrl eg: http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
* @return http://localhost:8082/oauthcallback
*/
def getStaticPortionOfRedirectURL(redirectUrl: String): Box[String] = {
tryo(redirectUrl.split("\\?")(0)) //return everything before the "?"
}
/**
* extract clean redirect url from input value, because input may have some parameters, such as the following examples <br/>
* eg1: http://localhost:8082/oauthcallback?....--> http://localhost:8082 <br/>
* eg2: http://localhost:8016?oautallback?=3NLMGV ...--> http://localhost:8016
*
* @param redirectUrl -> http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
* @return hostOnlyOfRedirectURL-> http://localhost:8082
*/
@deprecated("We can not only use hostname as the redirectUrl, now add new method `getStaticPortionOfRedirectURL` ","05.12.2023")
def getHostOnlyOfRedirectURL(redirectUrl: String): Box[String] = {
val url = new URL(redirectUrl) //eg: http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018
val protocol = url.getProtocol() // http
val authority = url.getAuthority()// localhost:8082, this will contain the port.
tryo(s"$protocol://$authority") // http://localhost:8082
}
/**
@ -461,7 +484,7 @@ object Helper extends Loggable {
}else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("consumer_key")){
result.asInstanceOf[Box[String]].filter(APIUtil.basicConsumerKeyValidation(_)==SILENCE_IS_GOLDEN)
}else if((args.length>0) && args.apply(0).toString.equalsIgnoreCase("redirectUrl")){
result.asInstanceOf[Box[String]].filter(APIUtil.basicUrlValidation(_))
result.asInstanceOf[Box[String]].filter(APIUtil.basicUriAndQueryStringValidation(_))
} else{
result.asInstanceOf[Box[String]].filter(APIUtil.checkMediumString(_)==SILENCE_IS_GOLDEN)
}

View File

@ -1,101 +0,0 @@
package code.bankconnectors.vMay2019
/*
Open Bank Project - API
Copyright (C) 2011-2019, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
*/
import code.actorsystem.ObpActorInit
import code.api.JSONFactoryGateway.PayloadOfJwtJSON
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
import code.bankconnectors.Connector
import code.bankconnectors.storedprocedure.StoredProcedureConnector_vDec2019
import code.bankconnectors.vSept2018._
import code.kafka.KafkaHelper
import code.setup.{DefaultUsers, KafkaSetup, ServerSetupWithTestData}
import com.openbankproject.commons.dto.InBoundGetBanks
import com.openbankproject.commons.model._
import net.liftweb.common.{Box, Failure, Full}
import org.scalatest.Tag
class StoredProcedureConnector_vDec2019Test extends ServerSetupWithTestData with DefaultUsers with ObpActorInit{
override implicit val formats = CustomJsonFormats.formats
object StoredProcedureConnector_vDec2019Test extends Tag("StoredProcedureConnector_vDec2019")
val callContext = Some(
CallContext(
gatewayLoginRequestPayload = Some(PayloadOfJwtJSON(
login_user_name = "",
is_first = false,
app_id = "",
app_name = "",
time_stamp = "",
cbs_token = Some(""),
cbs_id = "",
session_id = Some(""))),
user = Full(resourceUser1)
)
)
val PropsConnectorVersion = APIUtil.getPropsValue("connector").openOrThrowException("connector props filed `connector` not set")
feature("Test all stored_procedure methods") {
if (PropsConnectorVersion == "stored_procedure_vDec2019") {
// scenario("test `checkBankAccountExists` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
// val checkBankAccountExists = StoredProcedureConnector_vDec2019.checkBankAccountExists(testBankId1,testAccountId1,callContext)
// getValueFromFuture(checkBankAccountExists)._1.isDefined equals (true)
// }
//
// scenario("test `getBankAccounts` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
// val checkBankAccountExists = StoredProcedureConnector_vDec2019.checkBankAccountExists(testBankId1,testAccountId1,callContext)
// getValueFromFuture(checkBankAccountExists)._1.isDefined equals (true)
// }
// scenario("test `getBank` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
// val transantionRequests210 = StoredProcedureConnector_vDec2019.getBank(testBankId1, callContext)
// getValueFromFuture(transantionRequests210).isDefined equals (true)
// }
//
//
// scenario("test `getBanks` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
// val transantionRequests210 = StoredProcedureConnector_vDec2019.getBanks(callContext)
// getValueFromFuture(transantionRequests210).isDefined equals (true)
// }
//
// scenario("test `getTransactionRequests210` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
// val transantionRequests210: Box[(List[TransactionRequest], Option[CallContext])] = StoredProcedureConnector_vDec2019.getTransactionRequests210(resourceUser1, null, callContext)
// transantionRequests210.isDefined equals(true)
// }
scenario("test `getTransactions` method, there no need Adapter message for this method!", StoredProcedureConnector_vDec2019Test) {
val transactions = StoredProcedureConnector_vDec2019.getTransactions(testBankId1, testAccountId1, callContext, Nil)
val trans = getValueFromFuture(transactions)._1.openOrThrowException("Should not be empty!")
trans.head.description.isDefined equals (true)
}
} else {
ignore("ignore test getObpConnectorLoopback, if it is mapped connector", StoredProcedureConnector_vDec2019Test) {}
}
}
}

View File

@ -1,157 +0,0 @@
package code.bankconnectors.vMay2019
/*
Open Bank Project - API
Copyright (C) 2011-2019, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
*/
import code.api.JSONFactoryGateway.PayloadOfJwtJSON
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
import code.bankconnectors.Connector
import code.bankconnectors.vSept2018._
import code.kafka.KafkaHelper
import code.setup.{KafkaSetup, ServerSetupWithTestData}
import com.openbankproject.commons.dto.InBoundGetBanks
import com.openbankproject.commons.model._
import net.liftweb.common.{Box, Failure, Full}
import org.scalatest.Tag
class KafkaMappedConnector_vMay2019Test extends KafkaSetup with ServerSetupWithTestData {
override implicit val formats = CustomJsonFormats.formats
object kafkaTest extends Tag("kafkaTest")
val callContext = Some(
CallContext(
gatewayLoginRequestPayload = Some(PayloadOfJwtJSON(
login_user_name = "",
is_first = false,
app_id = "",
app_name = "",
time_stamp = "",
cbs_token = Some(""),
cbs_id = "",
session_id = Some(""))),
user = Full(resourceUser1)
)
)
val PropsConnectorVersion = APIUtil.getPropsValue("connector").openOrThrowException("connector props filed `connector` not set")
feature("Send and retrieve message") {
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
ignore("ignore test getObpConnectorLoopback, if it is mapped connector", kafkaTest) {}
} else
scenario("1st test `getObpConnectorLoopback` method, there no need Adapter message for this method!", kafkaTest) {
//This method is only used for `kafka` connector, should first set `connector=kafka_vSept2018` in test.default.props.
//and also need to set up `api_instance_id` and `remotedata.timeout` field for it.
val propsApiInstanceId = code.api.Constant.ApiInstanceId
val propsRemotedataTimeout = APIUtil.getPropsValue("remotedata.timeout").openOrThrowException("connector props filed `remotedata.timeout` not set")
PropsConnectorVersion contains ("kafka") should be(true)
propsApiInstanceId should be("1")
propsRemotedataTimeout should be("10")
When("We call this method, and get the response. ")
val future = KafkaHelper.echoKafkaServer
val result = future.getContent
Then("If it return value successfully, that mean api <--> kafka is working well. We only need check one filed of response.")
val connectorVersion = result.connectorVersion
connectorVersion should be(PropsConnectorVersion)
Then("For KafkaMappedConnector_vSept2018 connector, we need to make these two methods work `getAuthInfoFirstCbsCall` and `getAuthInfo`")
val firstAuthInfo: Box[AuthInfo] = for {
firstGetAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfoFirstCbsCall("","", callContext)
} yield {
(firstGetAuthInfo)
}
firstAuthInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
val authInfo: Box[AuthInfo] = for {
getAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfo(callContext)
} yield {
getAuthInfo
}
authInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
ignore("ignore test processRequest, if it is mapped connector", kafkaTest) {}
} else
scenario("Send and retrieve message directly to and from kafka", kafkaTest) {
val emptyStatusMessage = InboundStatusMessage("", "", "", "")
val inBound = InboundGetBanks(InboundAuthInfo("", ""), Status("", List(emptyStatusMessage)), List(InboundBank("1", "2", "3", "4")))
When("send a OutboundGetBanks message")
dispathResponse(inBound)
val req = OutboundGetBanks(AuthInfo())
val future = processRequest[InboundGetBanks](req)
val result: Box[InboundGetBanks] = future.getContent
result should be(Full(inBound))
}
}
feature("Test the getBank error cases") {
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
ignore("ignore test getBanks, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBanksFuture -- status.hasError", kafkaTest) {
val inbound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InBoundGetBanks]).map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetBanks]
//This inBound.status.errorCode != "", so it will throw the error back.
val expectedValue = Failure("INTERNAL-"+ inbound.status.errorCode+". + CoreBank-Status:" + inbound.status.backendMessages)
dispathResponse(inbound)
val future = Connector.connector.vend.getBanks(callContext)
dispathResponse(inbound)
val result = future.getContent
result should be(expectedValue)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star") {
ignore("ignore test getBanksFuture -- status.hasNoError, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBanksFuture -- status.hasNoError", kafkaTest) {
val inbound = Connector.connector.vend.messageDocs
.filter(_.exampleInboundMessage.isInstanceOf[InBoundGetBanks])
.map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetBanks]
.copy(status = Status("", Nil)) // This will set errorCode to "", no it works
//This inBound.status.errorCode != "", so it will throw the error back.
val expectedValue = Full(inbound.data.head.bankId).toString
dispathResponse(inbound)
val future = Connector.connector.vend.getBanks(callContext)
dispathResponse(inbound)
val result = future.getContent
result.map(_._1.head.bankId).toString should be(expectedValue)
}
}
}

View File

@ -1,401 +0,0 @@
package code.kafka
import java.util.{Date, UUID}
import code.api.JSONFactoryGateway.PayloadOfJwtJSON
import code.api.util.{APIUtil, CallContext, CustomJsonFormats}
import code.api.v2_1_0.TransactionRequestBodyCommonJSON
import code.bankconnectors.Connector
import code.bankconnectors.vSept2018._
import code.setup.{KafkaSetup, ServerSetupWithTestData}
import com.openbankproject.commons.dto.{InBoundGetKycChecks, InBoundGetKycMedias, InBoundGetKycStatuses}
import com.openbankproject.commons.model._
import net.liftweb.common.{Box, Full}
import org.scalatest.Tag
import scala.collection.immutable.List
class KafkaTest extends KafkaSetup with ServerSetupWithTestData {
override implicit val formats = CustomJsonFormats.formats
object kafkaTest extends Tag("kafkaTest")
val callContext = Some(
CallContext(
gatewayLoginRequestPayload = Some(PayloadOfJwtJSON(
login_user_name = "",
is_first = false,
app_id = "",
app_name = "",
time_stamp = "",
cbs_token = Some(""),
cbs_id = "",
session_id = Some(""))),
user = Full(resourceUser1)
)
)
val PropsConnectorVersion = APIUtil.getPropsValue("connector").openOrThrowException("connector props filed `connector` not set")
feature("Send and retrieve message") {
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getObpConnectorLoopback, if it is mapped connector", kafkaTest) {}
} else
scenario("1st test `getObpConnectorLoopback` method, there no need Adapter message for this method!", kafkaTest) {
//This method is only used for `kafka` connector, should first set `connector=kafka_vSept2018` in test.default.props.
//and also need to set up `api_instance_id` and `remotedata.timeout` field for it.
val propsApiInstanceId = code.api.Constant.ApiInstanceId
val propsRemotedataTimeout = APIUtil.getPropsValue("remotedata.timeout").openOrThrowException("connector props filed `remotedata.timeout` not set")
PropsConnectorVersion contains ("kafka") should be (true)
propsApiInstanceId should be ("1")
propsRemotedataTimeout should be ("10")
When("We call this method, and get the response. ")
val future = KafkaHelper.echoKafkaServer
val result = future.getContent
Then("If it return value successfully, that mean api <--> kafka is working well. We only need check one filed of response.")
val connectorVersion= result.connectorVersion
connectorVersion should be (PropsConnectorVersion)
Then("For KafkaMappedConnector_vSept2018 connector, we need to make these two methods work `getAuthInfoFirstCbsCall` and `getAuthInfo`")
val firstAuthInfo: Box[AuthInfo] = for{
firstGetAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfoFirstCbsCall("","", callContext)
} yield {
(firstGetAuthInfo)
}
firstAuthInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
val authInfo: Box[AuthInfo] = for{
getAuthInfo <- KafkaMappedConnector_vSept2018.getAuthInfo(callContext)
} yield {
getAuthInfo
}
authInfo.openOrThrowException("firstAuthInfo Can not be empty here. ")
}
// if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
// ignore("ignore test processRequest, if it is mapped connector", kafkaTest) {}
// } else
// scenario("Send and retrieve message directly to and from kafka", kafkaTest) {
// val emptyStatusMessage = InboundStatusMessage("", "", "", "")
// val inBound = InboundGetBanks(InboundAuthInfo("", ""), Status("", List(emptyStatusMessage)), List(InboundBank("1", "2", "3", "4")))
// When("send a OutboundGetBanks message")
//
// dispathResponse(inBound)
// val req = OutboundGetBanks(AuthInfo())
//
// val future = processRequest[InboundGetBanks](req)
// val result: Box[InboundGetBanks] = future.getContent
//
// result should be (Full(inBound))
// }
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getKycStatuses, if it is mapped connector", kafkaTest) {}
} else
scenario("test `getKycStatuses` method",kafkaTest) {
When("send a OutboundGetKycStatuses api message")
val emptyStatusMessage = InboundStatusMessage("", "", "", "")
val kycStatusCommons = KycStatusCommons(bankId = "hello_bank_id", customerId = "hello_customer_id", customerNumber = "hello_customer_number", ok = true, date = new Date())
val singleInboundBank = List(kycStatusCommons)
val inboundAdapterCallContext = InboundAdapterCallContext(correlationId="some_correlationId")
val inBound = InBoundGetKycStatuses(inboundAdapterCallContext, Status("", List(emptyStatusMessage)), singleInboundBank)
dispathResponse(inBound)
val future = Connector.connector.vend.getKycStatuses(kycStatusCommons.customerId, Some(CallContext()))
val result: (Box[List[KycStatus]], Option[CallContext]) = future.getContent
val expectResult = Full(singleInboundBank)
result._1.toString should be (expectResult.toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getKycChecks, if it is mapped connector", kafkaTest) {}
} else
scenario("test `getKycChecks` method", kafkaTest) {
When("send a OutboundGetKycChecks api message")
val inBound = Connector.connector.vend.messageDocs.filter(_.process =="obp.getKycChecks").map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetKycChecks]
dispathResponse(inBound)
val future = Connector.connector.vend.getKycChecks(inBound.data.head.customerId, Some(CallContext()))
val result: (Box[List[KycCheck]], Option[CallContext]) = future.getContent
val expectResult = Full(inBound.data)
result._1.toString should be (expectResult.toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getKycMedias, if it is mapped connector", kafkaTest) {}
} else
scenario("test `getKycMedias` method",kafkaTest) {
When("send a OutboundetKycMedias api message")
val inBound = Connector.connector.vend.messageDocs.filter(_.process =="obp.getKycMedias").map(_.exampleInboundMessage).head.asInstanceOf[InBoundGetKycMedias]
dispathResponse(inBound)
val future = Connector.connector.vend.getKycMedias(inBound.data.head.customerId, Some(CallContext()))
val result: (Box[List[KycMedia]], Option[CallContext]) = future.getContent
val expectResult = Full(inBound.data)
result._1.toString should be (expectResult.toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getAdapterInfo, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getAdapterInfo method",kafkaTest) {
When("send a getAdapterInfo api message")
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getAdapterInfo")).map(_.exampleInboundMessage).head.asInstanceOf[InboundAdapterInfo]
dispathResponse(inBound)
val future = Connector.connector.vend.getAdapterInfo(None)
val result: Box[(InboundAdapterInfoInternal, Option[CallContext])] = future.getContent
result.map(_._1) should be (Full(inBound.data))
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getUser, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getUser method",kafkaTest) {
When("send a getUser api message")
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getUser")).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetUserByUsernamePassword]
dispathResponse(inBound)
val box = Connector.connector.vend.getUser("username","password")
box.map(_.displayName) should be (Full(inBound.data.displayName))
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBanksFuture, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBanksFuture method", kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getBanks")).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBanks]
dispathResponse(inBound)
val future = Connector.connector.vend.getBanks(None)
val result = future.getContent
result.map(_._1.head.bankId).toString should be (Full(inBound.data.head.bankId).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBanks, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBanks method", kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.process.toString.contains("getBanks")).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBanks]
dispathResponse(inBound)
val box = Connector.connector.vend.getBanksLegacy(None)
box.map(_._1.head.bankId).toString should be (Full(inBound.data.head.bankId).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBank, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBank method", kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetBank]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBank]
dispathResponse(inBound)
val box = Connector.connector.vend.getBankLegacy(BankId(""), None)
box.map(_._1.bankId).toString should be (Full(inBound.data.bankId).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBankFuture, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBankFuture method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetBank]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetBank]
dispathResponse(inBound)
val future = Connector.connector.vend.getBank(BankId(""), None)
val result = future.getContent
result.map(_._1.bankId).toString should be (Full(inBound.data.bankId).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBankAccountsForUserFuture, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBankAccountsForUserFuture method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccounts]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccounts]
dispathResponse(inBound)
val future = Connector.connector.vend.getBankAccountsForUser("", "", callContext)
val result = future.getContent
result.map(_._1.head).toString should be (Full(inBound.data.head).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBankAccountsForUser, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBankAccountsForUser method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccounts]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccounts]
dispathResponse(inBound)
val box = Connector.connector.vend.getBankAccountsForUserLegacy("","", callContext)
box.map(_._1.head).toString should be (Full(inBound.data.head).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBankAccount, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBankAccount method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccountbyAccountID]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccountbyAccountID]
dispathResponse(inBound)
val box = Connector.connector.vend.getBankAccountLegacy(BankId(""), AccountId(""), callContext)
box.map(_._1.bankId).toString should be (Full(inBound.data.head.bankId).toString)
box.map(_._1.accountId).toString should be (Full(inBound.data.head.accountId).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getBankAccountFuture, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getBankAccountFuture method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetAccountbyAccountID]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetAccountbyAccountID]
dispathResponse(inBound)
val future = Connector.connector.vend.checkBankAccountExists(BankId(""), AccountId(""), callContext)
val result = future.getContent
result._1.map(_.accountId.value).toString should be (Full(inBound.data.head.accountId).toString)
result._1.map(_.bankId.value).toString should be (Full(inBound.data.head.bankId).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getChallengeThreshold, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getChallengeThreshold method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetChallengeThreshold]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetChallengeThreshold]
dispathResponse(inBound)
val future = Connector.connector.vend.getChallengeThreshold("","","","","","","", callContext)
val result = future.getContent
result._1.map(_.amount).toString should be (Full(inBound.data.amount).toString)
result._1.map(_.currency).toString should be (Full(inBound.data.currency).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test makePaymentv210, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test makePaymentv210 method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundCreateTransactionId]).map(_.exampleInboundMessage).head.asInstanceOf[InboundCreateTransactionId]
dispathResponse(inBound)
val fromAccount = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
val toAccount = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
val transactionRequestId = TransactionRequestId(UUID.randomUUID().toString)
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
val future = Connector.connector.vend.makePaymentv210(
fromAccount,
toAccount,
transactionRequestId,
transactionRequestCommonBody,
10,
"",
TransactionRequestType("SANDBOX_TAN"),
"",
callContext)
val result = future.getContent
result._1.map(_.value).toString should be (Full(inBound.data.id).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test createChallenge, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test createChallenge method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundCreateChallengeSept2018]).map(_.exampleInboundMessage).head.asInstanceOf[InboundCreateChallengeSept2018]
dispathResponse(inBound)
val account = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
val future = Connector.connector.vend.createChallenge(
account.bankId,
account.accountId,
"",
TransactionRequestType("SANDBOX_TAN"),
"",
None,
callContext)
val result = future.getContent
result._1.toString should be (Full(inBound.data.answer).toString)
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test createCounterparty, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test createCounterparty method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundCreateCounterparty]).map(_.exampleInboundMessage).head.asInstanceOf[InboundCreateCounterparty]
val outBound = Connector.connector.vend.messageDocs.filter(_.exampleOutboundMessage.isInstanceOf[OutboundCreateCounterparty]).map(_.exampleOutboundMessage).head.asInstanceOf[OutboundCreateCounterparty]
dispathResponse(inBound)
val account = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
val box = Connector.connector.vend.createCounterparty(
outBound.counterparty.name,
outBound.counterparty.description,
outBound.counterparty.currency,
outBound.counterparty.createdByUserId,
outBound.counterparty.thisBankId,
outBound.counterparty.thisAccountId,
outBound.counterparty.thisViewId,
outBound.counterparty.otherAccountRoutingScheme,
outBound.counterparty.otherAccountRoutingAddress,
outBound.counterparty.otherAccountSecondaryRoutingScheme,
outBound.counterparty.otherAccountSecondaryRoutingAddress,
outBound.counterparty.otherBankRoutingScheme,
outBound.counterparty.otherBankRoutingAddress,
outBound.counterparty.otherBranchRoutingScheme,
outBound.counterparty.otherBranchRoutingAddress,
outBound.counterparty.isBeneficiary,
outBound.counterparty.bespoke,
callContext)
box.map(_._1.counterpartyId) should be (Full(inBound.data.get.counterpartyId))
box.map(_._1.createdByUserId) should be (Full(inBound.data.get.createdByUserId))
}
if (PropsConnectorVersion =="mapped" || PropsConnectorVersion =="star"){
ignore("ignore test getTransactionRequests210, if it is mapped connector", kafkaTest) {}
} else
scenario(s"test getTransactionRequests210 method",kafkaTest) {
val inBound = Connector.connector.vend.messageDocs.filter(_.exampleInboundMessage.isInstanceOf[InboundGetTransactionRequests210]).map(_.exampleInboundMessage).head.asInstanceOf[InboundGetTransactionRequests210]
dispathResponse(inBound)
val account = BankAccountSept2018(KafkaMappedConnector_vSept2018.inboundAccountSept2018Example)
val transactionRequestCommonBody = TransactionRequestBodyCommonJSON(AmountOfMoneyJsonV121("",""),"")
val box = Connector.connector.vend.getTransactionRequests210(
resourceUser1,
account,
callContext)
box.map(_._1.head.body) should be (inBound.data.head.body)
}
}
}

View File

@ -1,76 +0,0 @@
package code.setup
import code.actorsystem.ObpActorSystem
import code.api.util.CustomJsonFormats
import code.kafka._
import code.util.Helper.MdcLoggable
import net.liftweb.json
import net.liftweb.json.Extraction
import net.manub.embeddedkafka.{EmbeddedKafka, EmbeddedKafkaConfig}
import org.apache.kafka.common.serialization.{StringDeserializer, StringSerializer}
import org.scalatest.{FeatureSpec, _}
import com.openbankproject.commons.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.{Duration, _}
trait KafkaSetup extends FeatureSpec with EmbeddedKafka with KafkaHelper
with GivenWhenThen with BeforeAndAfterAll
with Matchers with MdcLoggable {
implicit val formats = CustomJsonFormats.formats
implicit val config = EmbeddedKafkaConfig(kafkaPort = 9092, zooKeeperPort = 2181) //TODO the port should read from test.default.props, but fail
implicit val stringSerializer = new StringSerializer
implicit val stringDeserializer = new StringDeserializer
val requestMapResponseTopics:Map[String, String] = NorthSideConsumer.listOfTopics
.map(Topics.createTopicByClassName)
.map(pair => (pair.request, pair.response))
.toMap
val requestTopics = requestMapResponseTopics.keySet
override def beforeAll(): Unit = {
super.beforeAll()
EmbeddedKafka.start()
if(!OBPKafkaConsumer.primaryConsumer.started){
val actorSystem = ObpActorSystem.startLocalActorSystem
KafkaHelperActors.startLocalKafkaHelperWorkers(actorSystem)
// Start North Side Consumer if it's not already started
OBPKafkaConsumer.primaryConsumer.start()
}
}
override def afterAll(): Unit = {
super.afterAll()
OBPKafkaConsumer.primaryConsumer.complete()
EmbeddedKafka.stop()
}
/**
* send an object to kafka as response
*
* @param inBound inBound object that will send to kafka as a response
* @tparam T Outbound type
*/
def dispathResponse(inBound: AnyRef): Unit = {
val inBoundStr = inBound match {
case str: String => str
case _ =>json.compactRender(Extraction.decompose(inBound))
}
Future{
val requestKeyValue = consumeNumberKeyedMessagesFromTopics(requestTopics, 1, true)
val (requestTopic, keyValueList) = requestKeyValue.find(_._2.nonEmpty).get
val (key, _) = keyValueList.head
val responseTopic = requestMapResponseTopics(requestTopic)
publishToKafka(responseTopic, key, inBoundStr)
}
}
implicit class FutureExtract[T](future: Future[T]) {
def getContent: T = Await.result(future, 10 seconds)
}
}

View File

@ -698,12 +698,18 @@ class APIUtilTest extends FeatureSpec with Matchers with GivenWhenThen with Prop
APIUtil.getObpFormatOperationId("xxx") should be ("xxx")
}
feature("test APIUtil.basicUrlValidation method") {
feature("test APIUtil.basicUriAndQueryStringValidation method") {
val testString1 = "https%3A%2F%2Fapisandbox.openbankproject.com%2Foauth%2Fauthorize%3Fnext%3D%2Fen%2Fusers%2Fmyuser%26oauth_token%3DWTOBT2YRCTMI1BCCF4XAIKRXPLLZDZPFAIL5K03Z%26oauth_verifier%3D45381"
val testString2 = "http%3A%2F%2Flocalhost%3A8016%3Foauth_token%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
val testString3 = "myapp://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
val testString4 = "fb00000000:://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
val testString5 = "http://127.0.0.1:8000/oauth/authorize?next=/en/metrics/api/&oauth_token=TN0124OCPRCL4KUJRF5LNLVMRNHTVZPJDBS2PNWU&oauth_verifier=10470"
APIUtil.basicUrlValidation(testString1) should be (true)
APIUtil.basicUrlValidation(testString2) should be (true)
APIUtil.basicUriAndQueryStringValidation(testString1) should be (true)
APIUtil.basicUriAndQueryStringValidation(testString2) should be (true)
APIUtil.basicUriAndQueryStringValidation(testString3) should be (true)
APIUtil.basicUriAndQueryStringValidation(testString4) should be (true)
APIUtil.basicUriAndQueryStringValidation(testString5) should be (true)
}

View File

@ -35,13 +35,32 @@ import org.scalatest.{FeatureSpec, GivenWhenThen, Matchers}
class HelperTest extends FeatureSpec with Matchers with GivenWhenThen with PropsReset {
feature("test APIUtil.basicUrlValidation method") {
feature("test APIUtil.getStaticPortionOfRedirectURL method") {
// The redirectURl is `http://localhost:8082/oauthcallback`
val testString1 = "http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
val testString2 = "http://localhost:8082?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
val testString3 = "myapp://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
val testString4 = "fb00000000:://callback?oauth_token=%3DEBRZBMOPDXEUGGJP421FPFGK01IY2DGM5O3TLVSK%26oauth_verifier%3D63461"
val testString5 = "http://127.0.0.1:8000/oauth/authorize?next=/en/metrics/api/&oauth_token=TN0124OCPRCL4KUJRF5LNLVMRNHTVZPJDBS2PNWU&oauth_verifier=10470"
Helper.extractCleanRedirectURL(testString1).head should be("http://localhost:8082/oauthcallback")
Helper.extractCleanRedirectURL(testString2).head should be("http://localhost:8082")
Helper.getStaticPortionOfRedirectURL(testString1).head should be("http://localhost:8082/oauthcallback")
Helper.getStaticPortionOfRedirectURL(testString2).head should be("http://localhost:8082")
Helper.getStaticPortionOfRedirectURL(testString3).head should be("myapp://callback")
Helper.getStaticPortionOfRedirectURL(testString4).head should be("fb00000000:://callback")
Helper.getStaticPortionOfRedirectURL(testString5).head should be("http://127.0.0.1:8000/oauth/authorize")
}
feature("test APIUtil.getHostOnlyOfRedirectURL method") {
// The redirectURl is `http://localhost:8082/oauthcallback`
val testString1 = "http://localhost:8082/oauthcallback?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
val testString2 = "http://localhost:8082/oauthcallback"
val testString3 = "http://localhost:8082?oauth_token=G5AEA2U1WG404EGHTIGBHKRR4YJZAPPHWKOMNEEV&oauth_verifier=53018"
val testString4 = "http://localhost:8082"
Helper.getHostOnlyOfRedirectURL(testString1).head should be("http://localhost:8082")
Helper.getHostOnlyOfRedirectURL(testString2).head should be("http://localhost:8082")
Helper.getHostOnlyOfRedirectURL(testString3).head should be("http://localhost:8082")
Helper.getHostOnlyOfRedirectURL(testString4).head should be("http://localhost:8082")
}
}