Browse Source

server: Add getTransactionCount method to XSNService

scalafmt-draft
Alexis Hernandez 7 years ago
parent
commit
8dd032dacd
  1. 31
      server/app/com/xsn/explorer/services/XSNService.scala
  2. 12
      server/test/com/xsn/explorer/helpers/DummyXSNService.scala
  3. 53
      server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala
  4. 5
      server/test/controllers/TransactionsControllerSpec.scala

31
server/app/com/xsn/explorer/services/XSNService.scala

@ -20,6 +20,8 @@ trait XSNService {
def getTransaction(txid: TransactionId): FutureApplicationResult[Transaction]
def getAddressBalance(address: Address): FutureApplicationResult[AddressBalance]
def getTransactionCount(address: Address): FutureApplicationResult[Int]
}
class XSNServiceRPCImpl @Inject() (
@ -78,6 +80,33 @@ class XSNServiceRPCImpl @Inject() (
}
}
override def getTransactionCount(address: Address): FutureApplicationResult[Int] = {
val body = s"""
|{
| "jsonrpc": "1.0",
| "method": "getaddresstxids",
| "params": [
| { "addresses": ["${address.string}"] }
| ]
|}
|""".stripMargin
// the network returns 0 for valid addresses
val errorCodeMapper = Map(-5 -> AddressFormatError)
server
.post(body)
.map { response =>
val maybe = getResult[List[JsValue]](response, errorCodeMapper)
maybe.map(_.map(_.size)).getOrElse {
logger.warn(s"Unexpected response from XSN Server, status = ${response.status}, address = ${address.string}, response = ${response.body}")
Bad(XSNUnexpectedResponseError).accumulating
}
}
}
private def mapError(json: JsValue, errorCodeMapper: Map[Int, ApplicationError]): Option[ApplicationError] = {
val jsonErrorMaybe = (json \ "error")
.asOpt[JsValue]
@ -101,7 +130,7 @@ class XSNServiceRPCImpl @Inject() (
private def getResult[A](
response: WSResponse,
errorCodeMapper: Map[Int, ApplicationError] = Map.empty)(
errorCodeMapper: Map[Int, ApplicationError])(
implicit reads: Reads[A]): Option[ApplicationResult[A]] = {
Option(response)

12
server/test/com/xsn/explorer/helpers/DummyXSNService.scala

@ -0,0 +1,12 @@
package com.xsn.explorer.helpers
import com.alexitc.playsonify.core.FutureApplicationResult
import com.xsn.explorer.models.{Address, AddressBalance, Transaction, TransactionId}
import com.xsn.explorer.services.XSNService
class DummyXSNService extends XSNService {
override def getTransaction(txid: TransactionId): FutureApplicationResult[Transaction] = ???
override def getAddressBalance(address: Address): FutureApplicationResult[AddressBalance] = ???
override def getTransactionCount(address: Address): FutureApplicationResult[Int] = ???
}

53
server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala

@ -6,7 +6,7 @@ import com.xsn.explorer.helpers.Executors
import com.xsn.explorer.models.{Address, TransactionId}
import org.mockito.ArgumentMatchers._
import org.mockito.Mockito._
import org.scalactic.Bad
import org.scalactic.{Bad, Good}
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{MustMatchers, OptionValues, WordSpec}
@ -278,4 +278,55 @@ class XSNServiceRPCImplSpec extends WordSpec with MustMatchers with ScalaFutures
}
}
}
"getTransactionCount" should {
"return the number of transactions" in {
val responseBody =
"""
|{
| "result": [
| "3963203e8ff99c0effbc7c90ef1b534f7e60d9d4d1d131375bc73eb6af8b62d0",
| "56eff1fc3ec29277a039944a10826e1bd24685bec5e5c46c946846cb859dc14b",
| "d5718b83b6cec30e075c20dc61005a25a6eb707f14b92e89c2a9c4bc39635b5d",
| "9cd1d22e786b7b8722ce51f551c3c5af2053a52bd7694b9ef79e0a5d95053b19",
| "1dbf0277891ed39f8175fa08844eadbb6ed4b28464fbac0ba88464001192d79e",
| "2520ec229a76db8efa8e3b384582ac5c1969224a97f32475b957151f0c8cdfa7",
| "46d2f51afeab7aeb7adab821c374c7348ae0ff4edb7d0c9af995360630194cc8",
| "1a91406280e2a77dc0baf8a13491a977cba2d2dae6a8ba93fc6bbd3a7aeec4e5",
| "def0ae8bbfa45dca177f9c9f169e362bd25dee460a8ddc8c662e92e6968cd6d8"
| ],
| "error": null,
| "id": null
|}
""".stripMargin.trim
val address = Address.from("Xi3sQfMQsy2CzMZTrnKW6HFGp1VqFThdLw").get
val json = Json.parse(responseBody)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.post[String](anyString())(any())).thenReturn(Future.successful(response))
whenReady(service.getTransactionCount(address)) { result =>
result mustEqual Good(9)
}
}
"fail on invalid address" in {
val responseBody = """{"result":null,"error":{"code":-5,"message":"Invalid address"},"id":null}"""
val address = Address.from("Xi3sQfMQsy2CzMZTrnKW6HFGp1VqFThdLW").get
val json = Json.parse(responseBody)
when(response.status).thenReturn(200)
when(response.json).thenReturn(json)
when(request.post[String](anyString())(any())).thenReturn(Future.successful(response))
whenReady(service.getTransactionCount(address)) { result =>
result mustEqual Bad(AddressFormatError).accumulating
}
}
}
}

5
server/test/controllers/TransactionsControllerSpec.scala

@ -3,6 +3,7 @@ package controllers
import com.alexitc.playsonify.PublicErrorRenderer
import com.alexitc.playsonify.core.FutureApplicationResult
import com.xsn.explorer.errors.TransactionNotFoundError
import com.xsn.explorer.helpers.DummyXSNService
import com.xsn.explorer.models._
import com.xsn.explorer.services.XSNService
import controllers.common.MyAPISpec
@ -55,7 +56,7 @@ class TransactionsControllerSpec extends MyAPISpec {
TransactionVOUT(n = 2, value = BigDecimal("2343749.96562500"), scriptPubKeyType = "pubkeyhash", address = Address.from("XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL")))
)
val customXSNService = new XSNService {
val customXSNService = new DummyXSNService {
val map = Map(
"024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c" -> coinbaseTx,
"0834641a7d30d8a2d2b451617599670445ee94ed7736e146c13be260c576c641" -> nonCoinbaseTx,
@ -71,8 +72,6 @@ class TransactionsControllerSpec extends MyAPISpec {
Future.successful(result)
}
override def getAddressBalance(address: Address): FutureApplicationResult[AddressBalance] = ???
}
override val application = guiceApplicationBuilder

Loading…
Cancel
Save