Skip to content

Commit

Permalink
Fix RateLimiter tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kean committed Aug 18, 2024
1 parent 70b92f0 commit 123586a
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 54 deletions.
1 change: 0 additions & 1 deletion Sources/Nuke/Internal/RateLimiter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ final class RateLimiter {
let bucketRate = 1000.0 / bucket.rate
let delay = Int(2.1 * bucketRate) // 14 ms for rate 80 (default)
let bounds = min(100, max(15, delay))
// TODO: make sure this is correct
Task {
try? await Task.sleep(nanoseconds: UInt64(bounds) * 1_000_000)
self.executePendingTasks()
Expand Down
2 changes: 1 addition & 1 deletion Sources/Nuke/Pipeline/ImagePipeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public final class ImagePipeline {
}, completion: completion)
}

nonisolated func _loadImage(
private nonisolated func _loadImage(
with request: ImageRequest,
isDataTask: Bool = false,
progress: (@MainActor @Sendable (ImageResponse?, ImageTask.Progress) -> Void)?,
Expand Down
72 changes: 20 additions & 52 deletions Tests/NukeTests/RateLimiterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,102 +6,70 @@ import XCTest
@testable import Nuke

class RateLimiterTests: XCTestCase {
var queue: DispatchQueue!
var queueKey: DispatchSpecificKey<Void>!
var rateLimiter: RateLimiter!

override func setUp() {
super.setUp()

queue = DispatchQueue(label: "com.github.kean.rate-limiter-tests")

queueKey = DispatchSpecificKey<Void>()
queue.setSpecific(key: queueKey, value: ())

// Note: we set very short rate to avoid bucket form being refilled too quickly
rateLimiter = RateLimiter(rate: 10, burst: 2)
}

@ImagePipelineActor
func testThatBurstIsExecutedimmediately() {
// Given
var isExecuted = Array(repeating: false, count: 4)

// When
for i in isExecuted.indices {
queue.sync {
rateLimiter.execute {
isExecuted[i] = true
return true
}
rateLimiter.execute {
isExecuted[i] = true
return true
}
}

// Then
XCTAssertEqual(isExecuted, [true, true, false, false], "Expect first 2 items to be executed immediately")
}

@ImagePipelineActor
func testThatNotExecutedItemDoesntExtractFromBucket() {
// Given
var isExecuted = Array(repeating: false, count: 4)

// When
for i in isExecuted.indices {
queue.sync {
rateLimiter.execute {
isExecuted[i] = true
return i != 1 // important!
}
rateLimiter.execute {
isExecuted[i] = true
return i != 1 // important!
}
}

// Then
XCTAssertEqual(isExecuted, [true, true, true, false], "Expect first 2 items to be executed immediately")
}


@ImagePipelineActor
func testOverflow() {
// Given
var isExecuted = Array(repeating: false, count: 3)

// When
let expectation = self.expectation(description: "All work executed")
expectation.expectedFulfillmentCount = isExecuted.count

queue.sync {
for i in isExecuted.indices {
rateLimiter.execute {
isExecuted[i] = true
expectation.fulfill()
return true
}

for i in isExecuted.indices {
rateLimiter.execute {
isExecuted[i] = true
expectation.fulfill()
return true
}
}

// When time is passed
wait()

// Then
queue.sync {
XCTAssertEqual(isExecuted, [true, true, true], "Expect 3rd item to be executed after a short delay")
}
}

func testOverflowItemsExecutedOnSpecificQueue() {
// Given
let isExecuted = Array(repeating: false, count: 3)

let expectation = self.expectation(description: "All work executed")
expectation.expectedFulfillmentCount = isExecuted.count

queue.sync {
for _ in isExecuted.indices {
rateLimiter.execute {
expectation.fulfill()
// Then delayed task also executed on queue
XCTAssertNotNil(DispatchQueue.getSpecific(key: self.queueKey))
return true
}
}
}
wait()
XCTAssertEqual(isExecuted, [true, true, true], "Expect 3rd item to be executed after a short delay")
}
}

0 comments on commit 123586a

Please sign in to comment.