@@ -4,20 +4,23 @@ import java.net.InetAddress
44import java .time .{Clock , Instant , ZoneId }
55import java .util .concurrent .TimeUnit
66
7+ import akka .actor .ActorSystem
78import akka .http .scaladsl .model ._
89import akka .http .scaladsl .model .headers .{HttpOrigin , Origin }
910import akka .http .scaladsl .server .Route
1011import akka .http .scaladsl .testkit .ScalatestRouteTest
1112import akka .util .ByteString
1213import ch .megard .akka .http .cors .scaladsl .model .HttpOriginMatcher
13- import io .iohk .ethereum .jsonrpc .server .http .JsonRpcHttpServer .{JsonRpcHttpServerConfig , RateLimit }
14+ import io .iohk .ethereum .jsonrpc .server .http .JsonRpcHttpServer .{JsonRpcHttpServerConfig , RateLimitConfig }
1415import io .iohk .ethereum .jsonrpc .{JsonRpcController , JsonRpcHealthChecker , JsonRpcResponse }
1516import monix .eval .Task
1617import org .json4s .JsonAST .{JInt , JString }
1718import org .scalamock .scalatest .MockFactory
1819import org .scalatest .flatspec .AnyFlatSpec
1920import org .scalatest .matchers .should .Matchers
2021import akka .http .scaladsl .model .headers ._
22+ import io .iohk .ethereum .utils .Logger
23+ import io .iohk .ethereum .jsonrpc .server .controllers .JsonRpcBaseController
2124
2225import scala .concurrent .duration .FiniteDuration
2326
@@ -108,7 +111,7 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout
108111 val postRequest =
109112 HttpRequest (HttpMethods .POST , uri = " /" , entity = HttpEntity (MediaTypes .`application/json`, jsonRequest))
110113
111- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
114+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
112115 status shouldEqual StatusCodes .OK
113116 responseAs[String ] shouldEqual """ {"jsonrpc":"2.0","result":"this is a response","id":1}"""
114117 }
@@ -123,11 +126,11 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout
123126 val postRequest =
124127 HttpRequest (HttpMethods .POST , uri = " /" , entity = HttpEntity (MediaTypes .`application/json`, jsonRequest))
125128
126- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
129+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
127130 status shouldEqual StatusCodes .OK
128131 responseAs[String ] shouldEqual """ {"jsonrpc":"2.0","result":"this is a response","id":1}"""
129132 }
130- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
133+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
131134 status shouldEqual StatusCodes .TooManyRequests
132135 }
133136 }
@@ -143,7 +146,7 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout
143146 val postRequest =
144147 HttpRequest (HttpMethods .POST , uri = " /" , entity = HttpEntity (MediaTypes .`application/json`, jsonRequest))
145148
146- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
149+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
147150 status === StatusCodes .MethodNotAllowed
148151 }
149152 }
@@ -158,17 +161,17 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout
158161 val postRequest =
159162 HttpRequest (HttpMethods .POST , uri = " /" , entity = HttpEntity (MediaTypes .`application/json`, jsonRequest))
160163
161- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
164+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
162165 status shouldEqual StatusCodes .OK
163166 responseAs[String ] shouldEqual """ {"jsonrpc":"2.0","result":"this is a response","id":1}"""
164167 }
165- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
168+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
166169 status shouldEqual StatusCodes .TooManyRequests
167170 }
168171
169- fakeClock.advanceTime(10 )
172+ fakeClock.advanceTime(2 * serverConfigWithRateLimit.rateLimit.minRequestInterval.toMillis )
170173
171- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
174+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
172175 status shouldEqual StatusCodes .OK
173176 responseAs[String ] shouldEqual """ {"jsonrpc":"2.0","result":"this is a response","id":1}"""
174177 }
@@ -192,18 +195,18 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout
192195 jsonRequest)
193196 )
194197
195- postRequest ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
198+ postRequest ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
196199 status shouldEqual StatusCodes .OK
197200 responseAs[String ] shouldEqual """ {"jsonrpc":"2.0","result":"this is a response","id":1}"""
198201 }
199- postRequest2 ~> Route .seal(mockJsonRpcHttpServerWithIpRestriction .route) ~> check {
202+ postRequest2 ~> Route .seal(mockJsonRpcHttpServerWithRateLimit .route) ~> check {
200203 status shouldEqual StatusCodes .OK
201204 responseAs[String ] shouldEqual """ {"jsonrpc":"2.0","result":"this is a response","id":1}"""
202205 }
203206 }
204207
205208 trait TestSetup extends MockFactory {
206- val rateLimitConfig = new RateLimit {
209+ val rateLimitConfig = new RateLimitConfig {
207210 override val enabled : Boolean = false
208211 override val minRequestInterval : FiniteDuration = FiniteDuration .apply(5 , TimeUnit .SECONDS )
209212 override val latestTimestampCacheSize : Int = 1024
@@ -215,51 +218,66 @@ class JsonRpcHttpServerSpec extends AnyFlatSpec with Matchers with ScalatestRout
215218 override val interface : String = " "
216219 override val port : Int = 123
217220 override val corsAllowedOrigins = HttpOriginMatcher .*
218- override val rateLimit : RateLimit = rateLimitConfig
221+ override val rateLimit : RateLimitConfig = rateLimitConfig
219222 }
220223
221- val mockJsonRpcController = mock[JsonRpcController ]
222- val mockJsonRpcHealthChecker = mock[JsonRpcHealthChecker ]
223- val mockJsonRpcHttpServer = new JsonRpcHttpServer {
224- override val jsonRpcController = mockJsonRpcController
225- override val jsonRpcHealthChecker = mockJsonRpcHealthChecker
226- override val config : JsonRpcHttpServerConfig = serverConfig
227-
228- def run (): Unit = ()
229-
230- override def corsAllowedOrigins : HttpOriginMatcher = config.corsAllowedOrigins
224+ val rateLimitEnabledConfig = new RateLimitConfig {
225+ override val enabled : Boolean = true
226+ override val minRequestInterval : FiniteDuration = FiniteDuration .apply(5 , TimeUnit .SECONDS )
227+ override val latestTimestampCacheSize : Int = 1024
231228 }
232229
233- val corsAllowedOrigin = HttpOrigin (" http://localhost:3333" )
234-
235- val mockJsonRpcHttpServerWithCors = new JsonRpcHttpServer {
236- override val jsonRpcController = mockJsonRpcController
237- override val jsonRpcHealthChecker = mockJsonRpcHealthChecker
238- override val config : JsonRpcHttpServerConfig = serverConfig
239-
240- def run (): Unit = ()
241-
242- override def corsAllowedOrigins : HttpOriginMatcher = HttpOriginMatcher (corsAllowedOrigin)
230+ val serverConfigWithRateLimit = new JsonRpcHttpServerConfig {
231+ override val mode : String = " mockJsonRpc"
232+ override val enabled : Boolean = true
233+ override val interface : String = " "
234+ override val port : Int = 123
235+ override val corsAllowedOrigins = HttpOriginMatcher .*
236+ override val rateLimit : RateLimitConfig = rateLimitEnabledConfig
243237 }
244238
239+ val mockJsonRpcController = mock[JsonRpcController ]
240+ val mockJsonRpcHealthChecker = mock[JsonRpcHealthChecker ]
245241 val fakeClock = new FakeClock
246- val mockJsonRpcHttpServerWithIpRestriction = new JsonRpcHttpServer {
247- override val jsonRpcController = mockJsonRpcController
248- override val jsonRpcHealthChecker = mockJsonRpcHealthChecker
249- override val config : JsonRpcHttpServerConfig = serverConfig
250242
251- override val clock : Clock = fakeClock
243+ val mockJsonRpcHttpServer = new FakeJsonRpcHttpServer (
244+ mockJsonRpcController,
245+ mockJsonRpcHealthChecker,
246+ serverConfig,
247+ serverConfig.corsAllowedOrigins,
248+ fakeClock)
252249
253- override val config .rateLimit.`enabled` = true
254- override val config .rateLimit.minRequestInterval: FiniteDuration = config.rateLimit.minRequestInterval
255-
256- def run (): Unit = ()
257-
258- override def corsAllowedOrigins : HttpOriginMatcher = config.corsAllowedOrigins
259- }
250+ val corsAllowedOrigin = HttpOrigin (" http://localhost:3333" )
251+ val mockJsonRpcHttpServerWithCors = new FakeJsonRpcHttpServer (
252+ mockJsonRpcController,
253+ mockJsonRpcHealthChecker,
254+ serverConfig,
255+ HttpOriginMatcher (corsAllowedOrigin),
256+ fakeClock)
257+
258+ val mockJsonRpcHttpServerWithRateLimit = new FakeJsonRpcHttpServer (
259+ mockJsonRpcController,
260+ mockJsonRpcHealthChecker,
261+ serverConfigWithRateLimit,
262+ serverConfigWithRateLimit.corsAllowedOrigins,
263+ fakeClock)
260264 }
261265}
262266
267+ class FakeJsonRpcHttpServer (
268+ val jsonRpcController : JsonRpcBaseController ,
269+ val jsonRpcHealthChecker : JsonRpcHealthChecker ,
270+ val config : JsonRpcHttpServerConfig ,
271+ val cors : HttpOriginMatcher ,
272+ val testClock : Clock
273+ )(implicit val actorSystem : ActorSystem )
274+ extends JsonRpcHttpServer
275+ with Logger {
276+ def run (): Unit = ()
277+ override def corsAllowedOrigins : HttpOriginMatcher = cors
278+ override val clock = testClock
279+ }
280+
263281class FakeClock extends Clock {
264282
265283 var time : Instant = Instant .now()
0 commit comments