mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
rate-limits refactor for single point of truth 2
This commit is contained in:
parent
a9a7384088
commit
1eaaa50d8f
@ -4157,14 +4157,14 @@ object SwaggerDefinitionsJSON {
|
||||
)
|
||||
|
||||
lazy val activeCallLimitsJsonV600 = ActiveCallLimitsJsonV600(
|
||||
call_limits = List(callLimitJsonV600),
|
||||
considered_rate_limit_ids = List("80e1e0b2-d8bf-4f85-a579-e69ef36e3305"),
|
||||
active_at_date = DateWithDayExampleObject,
|
||||
total_per_second_call_limit = 100,
|
||||
total_per_minute_call_limit = 1000,
|
||||
total_per_hour_call_limit = -1,
|
||||
total_per_day_call_limit = -1,
|
||||
total_per_week_call_limit = -1,
|
||||
total_per_month_call_limit = -1
|
||||
active_per_second_rate_limit = 100,
|
||||
active_per_minute_rate_limit = 1000,
|
||||
active_per_hour_rate_limit = -1,
|
||||
active_per_day_rate_limit = -1,
|
||||
active_per_week_rate_limit = -1,
|
||||
active_per_month_rate_limit = -1
|
||||
)
|
||||
|
||||
lazy val accountWebhookPostJson = AccountWebhookPostJson(
|
||||
|
||||
@ -457,10 +457,10 @@ trait APIMethods600 {
|
||||
implementedInApiVersion,
|
||||
nameOf(getActiveCallLimitsAtDate),
|
||||
"GET",
|
||||
"/management/consumers/CONSUMER_ID/consumer/rate-limits/active-at-date/DATE",
|
||||
"/management/consumers/CONSUMER_ID/consumer/active-rate-limits/DATE",
|
||||
"Get Active Rate Limits at Date",
|
||||
s"""
|
||||
|Get the sum of rate limits at a certain date time. This returns a SUM of all the records that span that time.
|
||||
|Get the active rate limits for a consumer at a specific date. Returns the aggregated rate limits from all active records at that time.
|
||||
|
|
||||
|Date format: YYYY-MM-DDTHH:MM:SSZ (e.g. 1099-12-31T23:00:00Z)
|
||||
|
|
||||
@ -482,7 +482,7 @@ trait APIMethods600 {
|
||||
|
||||
|
||||
lazy val getActiveCallLimitsAtDate: OBPEndpoint = {
|
||||
case "management" :: "consumers" :: consumerId :: "consumer" :: "rate-limits" :: "active-at-date" :: dateString :: Nil JsonGet _ =>
|
||||
case "management" :: "consumers" :: consumerId :: "consumer" :: "active-rate-limits" :: dateString :: Nil JsonGet _ =>
|
||||
cc =>
|
||||
implicit val ec = EndpointContext(Some(cc))
|
||||
for {
|
||||
@ -494,8 +494,10 @@ trait APIMethods600 {
|
||||
format.parse(dateString)
|
||||
}
|
||||
rateLimit <- RateLimitingUtil.getActiveRateLimits(consumerId, date)
|
||||
rateLimitRecords <- RateLimitingDI.rateLimiting.vend.getActiveCallLimitsByConsumerIdAtDate(consumerId, date)
|
||||
rateLimitIds = rateLimitRecords.map(_.rateLimitingId)
|
||||
} yield {
|
||||
(JSONFactory600.createActiveCallLimitsJsonV600FromCallLimit(rateLimit, date), HttpCode.`200`(callContext))
|
||||
(JSONFactory600.createActiveCallLimitsJsonV600FromCallLimit(rateLimit, rateLimitIds, date), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -99,14 +99,14 @@ case class CallLimitJsonV600(
|
||||
)
|
||||
|
||||
case class ActiveCallLimitsJsonV600(
|
||||
call_limits: List[CallLimitJsonV600],
|
||||
considered_rate_limit_ids: List[String],
|
||||
active_at_date: java.util.Date,
|
||||
total_per_second_call_limit: Long,
|
||||
total_per_minute_call_limit: Long,
|
||||
total_per_hour_call_limit: Long,
|
||||
total_per_day_call_limit: Long,
|
||||
total_per_week_call_limit: Long,
|
||||
total_per_month_call_limit: Long
|
||||
active_per_second_rate_limit: Long,
|
||||
active_per_minute_rate_limit: Long,
|
||||
active_per_hour_rate_limit: Long,
|
||||
active_per_day_rate_limit: Long,
|
||||
active_per_week_rate_limit: Long,
|
||||
active_per_month_rate_limit: Long
|
||||
)
|
||||
|
||||
case class RateLimitV600(
|
||||
@ -574,32 +574,34 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
|
||||
rateLimitings: List[code.ratelimiting.RateLimiting],
|
||||
activeDate: java.util.Date
|
||||
): ActiveCallLimitsJsonV600 = {
|
||||
val callLimits = rateLimitings.map(createCallLimitJsonV600)
|
||||
val rateLimitIds = rateLimitings.map(_.rateLimitingId)
|
||||
ActiveCallLimitsJsonV600(
|
||||
call_limits = callLimits,
|
||||
considered_rate_limit_ids = rateLimitIds,
|
||||
active_at_date = activeDate,
|
||||
total_per_second_call_limit = rateLimitings.map(_.perSecondCallLimit).sum,
|
||||
total_per_minute_call_limit = rateLimitings.map(_.perMinuteCallLimit).sum,
|
||||
total_per_hour_call_limit = rateLimitings.map(_.perHourCallLimit).sum,
|
||||
total_per_day_call_limit = rateLimitings.map(_.perDayCallLimit).sum,
|
||||
total_per_week_call_limit = rateLimitings.map(_.perWeekCallLimit).sum,
|
||||
total_per_month_call_limit = rateLimitings.map(_.perMonthCallLimit).sum
|
||||
active_per_second_rate_limit = rateLimitings.map(_.perSecondCallLimit).sum,
|
||||
active_per_minute_rate_limit = rateLimitings.map(_.perMinuteCallLimit).sum,
|
||||
active_per_hour_rate_limit = rateLimitings.map(_.perHourCallLimit).sum,
|
||||
active_per_day_rate_limit = rateLimitings.map(_.perDayCallLimit).sum,
|
||||
active_per_week_rate_limit = rateLimitings.map(_.perWeekCallLimit).sum,
|
||||
active_per_month_rate_limit = rateLimitings.map(_.perMonthCallLimit).sum
|
||||
)
|
||||
}
|
||||
|
||||
def createActiveCallLimitsJsonV600FromCallLimit(
|
||||
|
||||
rateLimit: code.api.util.RateLimitingJson.CallLimit,
|
||||
rateLimitIds: List[String],
|
||||
activeDate: java.util.Date
|
||||
): ActiveCallLimitsJsonV600 = {
|
||||
ActiveCallLimitsJsonV600(
|
||||
call_limits = List.empty,
|
||||
considered_rate_limit_ids = rateLimitIds,
|
||||
active_at_date = activeDate,
|
||||
total_per_second_call_limit = rateLimit.per_second,
|
||||
total_per_minute_call_limit = rateLimit.per_minute,
|
||||
total_per_hour_call_limit = rateLimit.per_hour,
|
||||
total_per_day_call_limit = rateLimit.per_day,
|
||||
total_per_week_call_limit = rateLimit.per_week,
|
||||
total_per_month_call_limit = rateLimit.per_month
|
||||
active_per_second_rate_limit = rateLimit.per_second,
|
||||
active_per_minute_rate_limit = rateLimit.per_minute,
|
||||
active_per_hour_rate_limit = rateLimit.per_hour,
|
||||
active_per_day_rate_limit = rateLimit.per_day,
|
||||
active_per_week_rate_limit = rateLimit.per_week,
|
||||
active_per_month_rate_limit = rateLimit.per_month
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ import java.time.format.DateTimeFormatter
|
||||
import java.time.{ZoneOffset, ZonedDateTime}
|
||||
import java.util.Date
|
||||
|
||||
class CallLimitsTest extends V600ServerSetup {
|
||||
class RateLimitsTest extends V600ServerSetup {
|
||||
|
||||
object VersionOfApi extends Tag(ApiVersion.v6_0_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations6_0_0.createCallLimits))
|
||||
@ -171,15 +171,15 @@ class CallLimitsTest extends V600ServerSetup {
|
||||
val currentDateString = ZonedDateTime
|
||||
.now(ZoneOffset.UTC)
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"))
|
||||
val getRequest = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "rate-limits" / "active-at-date" / currentDateString).GET <@ (user1)
|
||||
val getRequest = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "active-rate-limits" / currentDateString).GET <@ (user1)
|
||||
val getResponse = makeGetRequest(getRequest)
|
||||
|
||||
Then("We should get a 200")
|
||||
getResponse.code should equal(200)
|
||||
And("we should get the active call limits response")
|
||||
val activeCallLimits = getResponse.body.extract[ActiveCallLimitsJsonV600]
|
||||
activeCallLimits.call_limits.size == 0
|
||||
activeCallLimits.total_per_second_call_limit == 0L
|
||||
activeCallLimits.considered_rate_limit_ids.size >= 0
|
||||
activeCallLimits.active_per_second_rate_limit == 0L
|
||||
}
|
||||
|
||||
scenario("We will try to get active call limits without proper role", ApiEndpoint3, VersionOfApi) {
|
||||
@ -189,7 +189,7 @@ class CallLimitsTest extends V600ServerSetup {
|
||||
val currentDateString = ZonedDateTime
|
||||
.now(ZoneOffset.UTC)
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"))
|
||||
val getRequest = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "rate-limits" / "active-at-date" / currentDateString).GET <@ (user1)
|
||||
val getRequest = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "active-rate-limits" / currentDateString).GET <@ (user1)
|
||||
val getResponse = makeGetRequest(getRequest)
|
||||
|
||||
Then("We should get a 403")
|
||||
@ -197,5 +197,71 @@ class CallLimitsTest extends V600ServerSetup {
|
||||
And("error should be " + UserHasMissingRoles + CanGetRateLimits)
|
||||
getResponse.body.extract[ErrorMessage].message should equal(UserHasMissingRoles + CanGetRateLimits)
|
||||
}
|
||||
|
||||
scenario("We will get aggregated call limits for two overlapping rate limit records", ApiEndpoint3, VersionOfApi) {
|
||||
Given("We create two call limit records with overlapping date ranges")
|
||||
val Some((c, _)) = user1
|
||||
val consumerId = Consumers.consumers.vend.getConsumerByConsumerKey(c.key).map(_.consumerId.get).getOrElse("")
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateRateLimits.toString)
|
||||
|
||||
// Create first rate limit record
|
||||
val fromDate1 = new Date()
|
||||
val toDate1 = new Date(System.currentTimeMillis() + 172800000L) // +2 days
|
||||
val rateLimit1 = CallLimitPostJsonV600(
|
||||
from_date = fromDate1,
|
||||
to_date = toDate1,
|
||||
api_version = Some("v6.0.0"),
|
||||
api_name = Some("testEndpoint1"),
|
||||
bank_id = None,
|
||||
per_second_call_limit = "10",
|
||||
per_minute_call_limit = "100",
|
||||
per_hour_call_limit = "1000",
|
||||
per_day_call_limit = "5000",
|
||||
per_week_call_limit = "-1",
|
||||
per_month_call_limit = "-1"
|
||||
)
|
||||
val request1 = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "rate-limits").POST <@ (user1)
|
||||
val createResponse1 = makePostRequest(request1, write(rateLimit1))
|
||||
createResponse1.code should equal(201)
|
||||
|
||||
// Create second rate limit record with same date range
|
||||
val rateLimit2 = CallLimitPostJsonV600(
|
||||
from_date = fromDate1,
|
||||
to_date = toDate1,
|
||||
api_version = Some("v6.0.0"),
|
||||
api_name = Some("testEndpoint2"),
|
||||
bank_id = None,
|
||||
per_second_call_limit = "5",
|
||||
per_minute_call_limit = "50",
|
||||
per_hour_call_limit = "500",
|
||||
per_day_call_limit = "2500",
|
||||
per_week_call_limit = "-1",
|
||||
per_month_call_limit = "-1"
|
||||
)
|
||||
val request2 = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "rate-limits").POST <@ (user1)
|
||||
val createResponse2 = makePostRequest(request2, write(rateLimit2))
|
||||
createResponse2.code should equal(201)
|
||||
|
||||
When("We get active call limits at a date within the overlapping range")
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetRateLimits.toString)
|
||||
val targetDate = ZonedDateTime
|
||||
.now(ZoneOffset.UTC)
|
||||
.plusDays(1) // Check 1 day from now (within the range)
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"))
|
||||
val getRequest = (v6_0_0_Request / "management" / "consumers" / consumerId / "consumer" / "active-rate-limits" / targetDate).GET <@ (user1)
|
||||
val getResponse = makeGetRequest(getRequest)
|
||||
|
||||
Then("We should get a 200")
|
||||
getResponse.code should equal(200)
|
||||
|
||||
And("the totals should be the sum of both records (using single source of truth aggregation)")
|
||||
val activeCallLimits = getResponse.body.extract[ActiveCallLimitsJsonV600]
|
||||
activeCallLimits.active_per_second_rate_limit should equal(15L) // 10 + 5
|
||||
activeCallLimits.active_per_minute_rate_limit should equal(150L) // 100 + 50
|
||||
activeCallLimits.active_per_hour_rate_limit should equal(1500L) // 1000 + 500
|
||||
activeCallLimits.active_per_day_rate_limit should equal(7500L) // 5000 + 2500
|
||||
activeCallLimits.active_per_week_rate_limit should equal(-1L) // -1 (both are -1, so unlimited)
|
||||
activeCallLimits.active_per_month_rate_limit should equal(-1L) // -1 (both are -1, so unlimited)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user