|
| 1 | +package io.iohk.ethereum.faucet.jsonrpc |
| 2 | + |
| 3 | +import akka.actor.{ActorRef, ActorSystem} |
| 4 | +import akka.testkit.{TestKit, TestProbe} |
| 5 | +import akka.util.ByteString |
| 6 | +import io.iohk.ethereum.domain.Address |
| 7 | +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerMsg |
| 8 | +import io.iohk.ethereum.faucet.FaucetHandler.FaucetHandlerResponse.{ |
| 9 | + FaucetIsUnavailable, |
| 10 | + StatusResponse, |
| 11 | + TransactionSent, |
| 12 | + WalletRpcClientError |
| 13 | +} |
| 14 | +import io.iohk.ethereum.faucet.FaucetStatus.WalletAvailable |
| 15 | +import io.iohk.ethereum.faucet.jsonrpc.FaucetDomain.{SendFundsRequest, StatusRequest} |
| 16 | +import io.iohk.ethereum.faucet.{FaucetConfig, SupervisorConfig} |
| 17 | +import io.iohk.ethereum.jsonrpc.JsonRpcError |
| 18 | +import io.iohk.ethereum.testing.ActorsTesting.simpleAutoPilot |
| 19 | +import io.iohk.ethereum.{NormalPatience, WithActorSystemShutDown} |
| 20 | +import monix.eval.Task |
| 21 | +import monix.execution.Scheduler.Implicits.global |
| 22 | +import org.bouncycastle.util.encoders.Hex |
| 23 | +import org.scalactic.TypeCheckedTripleEquals |
| 24 | +import org.scalamock.scalatest.MockFactory |
| 25 | +import org.scalatest.OptionValues |
| 26 | +import org.scalatest.concurrent.ScalaFutures |
| 27 | +import org.scalatest.flatspec.AnyFlatSpecLike |
| 28 | +import org.scalatest.matchers.should.Matchers |
| 29 | + |
| 30 | +import scala.concurrent.duration._ |
| 31 | + |
| 32 | +class FaucetRpcServiceSpec |
| 33 | + extends TestKit(ActorSystem("ActorSystem_DebugFaucetRpcServiceSpec")) |
| 34 | + with AnyFlatSpecLike |
| 35 | + with WithActorSystemShutDown |
| 36 | + with Matchers |
| 37 | + with ScalaFutures |
| 38 | + with OptionValues |
| 39 | + with MockFactory |
| 40 | + with NormalPatience |
| 41 | + with TypeCheckedTripleEquals { |
| 42 | + |
| 43 | + "FaucetRpcService" should "answer txHash correctly when the wallet is available and the requested send funds be successfully" in new TestSetup { |
| 44 | + val address: Address = Address("0x00") |
| 45 | + val request: SendFundsRequest = SendFundsRequest(address) |
| 46 | + val txHash: ByteString = ByteString(Hex.decode("112233")) |
| 47 | + |
| 48 | + fHandler.setAutoPilot(simpleAutoPilot { case FaucetHandlerMsg.SendFunds(`address`) => |
| 49 | + TransactionSent(txHash) |
| 50 | + }) |
| 51 | + faucetRpcService.sendFunds(request).runSyncUnsafe(Duration.Inf) match { |
| 52 | + case Left(error) => fail(s"failure with error: $error") |
| 53 | + case Right(response) => response.txId shouldBe txHash |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + it should "answer WalletRpcClientError when the wallet is available and the requested send funds be failure" in new TestSetup { |
| 58 | + val address: Address = Address("0x00") |
| 59 | + val request: SendFundsRequest = SendFundsRequest(address) |
| 60 | + val clientError: String = "Parser error" |
| 61 | + |
| 62 | + fHandler.setAutoPilot(simpleAutoPilot { case FaucetHandlerMsg.SendFunds(`address`) => |
| 63 | + WalletRpcClientError(clientError) |
| 64 | + }) |
| 65 | + faucetRpcService.sendFunds(request).runSyncUnsafe(Duration.Inf) match { |
| 66 | + case Right(_) => fail() |
| 67 | + case Left(error) => error shouldBe JsonRpcError.LogicError(s"Faucet error: $clientError") |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + it should "answer FaucetIsUnavailable when tried to send funds and the wallet is unavailable" in new TestSetup { |
| 72 | + val address: Address = Address("0x00") |
| 73 | + val request: SendFundsRequest = SendFundsRequest(address) |
| 74 | + |
| 75 | + fHandler.setAutoPilot(simpleAutoPilot { case FaucetHandlerMsg.SendFunds(`address`) => |
| 76 | + FaucetIsUnavailable |
| 77 | + }) |
| 78 | + faucetRpcService.sendFunds(request).runSyncUnsafe(Duration.Inf) match { |
| 79 | + case Right(_) => fail() |
| 80 | + case Left(error) => |
| 81 | + error shouldBe JsonRpcError.LogicError("Faucet is unavailable: Please try again in a few more seconds") |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + it should "answer FaucetIsUnavailable when tried to get status and the wallet is unavailable" in new TestSetup { |
| 86 | + fHandler.setAutoPilot(simpleAutoPilot { case FaucetHandlerMsg.Status => |
| 87 | + FaucetIsUnavailable |
| 88 | + }) |
| 89 | + faucetRpcService.status(StatusRequest()).runSyncUnsafe(Duration.Inf) match { |
| 90 | + case Right(_) => fail() |
| 91 | + case Left(error) => |
| 92 | + error shouldBe JsonRpcError.LogicError("Faucet is unavailable: Please try again in a few more seconds") |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + it should "answer WalletAvailable when tried to get status and the wallet is available" in new TestSetup { |
| 97 | + fHandler.setAutoPilot(simpleAutoPilot { case FaucetHandlerMsg.Status => |
| 98 | + StatusResponse(WalletAvailable) |
| 99 | + }) |
| 100 | + faucetRpcService.status(StatusRequest()).runSyncUnsafe(Duration.Inf) match { |
| 101 | + case Left(error) => fail(s"failure with error: $error") |
| 102 | + case Right(response) => response shouldBe FaucetDomain.StatusResponse(WalletAvailable) |
| 103 | + } |
| 104 | + } |
| 105 | + |
| 106 | + it should "answer internal error when tried to send funds but the Faucet Handler is disable" in new TestSetup { |
| 107 | + val address: Address = Address("0x00") |
| 108 | + val request: SendFundsRequest = SendFundsRequest(address) |
| 109 | + |
| 110 | + faucetRpcServiceWithoutFaucetHandler.sendFunds(request).runSyncUnsafe(Duration.Inf) match { |
| 111 | + case Right(_) => fail() |
| 112 | + case Left(error) => |
| 113 | + error shouldBe JsonRpcError.InternalError |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + it should "answer internal error when tried to get status but the Faucet Handler is disable" in new TestSetup { |
| 118 | + val address: Address = Address("0x00") |
| 119 | + val request: SendFundsRequest = SendFundsRequest(address) |
| 120 | + |
| 121 | + faucetRpcServiceWithoutFaucetHandler.status(StatusRequest()).runSyncUnsafe(Duration.Inf) match { |
| 122 | + case Right(_) => fail() |
| 123 | + case Left(error) => |
| 124 | + error shouldBe JsonRpcError.InternalError |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + class TestSetup(implicit system: ActorSystem) { |
| 129 | + |
| 130 | + val config: FaucetConfig = FaucetConfig( |
| 131 | + walletAddress = Address("0x99"), |
| 132 | + walletPassword = "", |
| 133 | + txGasPrice = 10, |
| 134 | + txGasLimit = 20, |
| 135 | + txValue = 1, |
| 136 | + rpcAddress = "", |
| 137 | + keyStoreDir = "", |
| 138 | + minRequestInterval = 10.seconds, |
| 139 | + handlerTimeout = 10.seconds, |
| 140 | + responseTimeout = 10.seconds, |
| 141 | + supervisor = mock[SupervisorConfig], |
| 142 | + shutdownTimeout = 15.seconds |
| 143 | + ) |
| 144 | + |
| 145 | + val fHandler = TestProbe() |
| 146 | + |
| 147 | + val faucetRpcService: FaucetRpcService = new FaucetRpcService(config) { |
| 148 | + |
| 149 | + override def faucetHandler()(implicit system: ActorSystem): Task[ActorRef] = { |
| 150 | + Task(fHandler.ref) |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + val faucetRpcServiceWithoutFaucetHandler: FaucetRpcService = new FaucetRpcService(config) { |
| 155 | + override def faucetHandler()(implicit system: ActorSystem): Task[ActorRef] = { |
| 156 | + Task.raiseError(new RuntimeException("time out")) |
| 157 | + } |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | +} |
0 commit comments