···2222 /// Epoch timestamp of the last time the rate limiter was updated.
2323 ///
2424 last_update: Option(Int),
2525+ /// Timestamp that overrides the current time for testing purposes.
2626+ ///
2727+ now: Option(Int),
2528 )
2629}
27302831/// Updates the state to reflect the passage of time.
2932///
3033fn refill_bucket(state: State) -> State {
3131- let now = utils.now()
3434+ let now = case state.now {
3535+ None -> utils.now()
3636+ Some(now) -> now
3737+ }
3238 let time_diff = case state.last_update {
3339 None -> 0
3440 Some(last_update) -> now - last_update
···6369 /// Returns True if the token bucket is full.
6470 ///
6571 HasFullBucket(reply_with: Subject(Bool))
7272+7373+ /// Set the current time for testing purposes.
7474+ ///
7575+ SetNow(now: Int)
6676}
67776878fn handle_message(message: Message, state: State) -> actor.Next(Message, State) {
···8797 actor.send(client, result)
8898 actor.continue(state)
8999 }
100100+101101+ SetNow(now) -> actor.continue(State(..state, now: Some(now)))
90102 }
91103}
92104···102114 token_rate: token_rate,
103115 token_count: max_token_count,
104116 last_update: None,
117117+ now: None,
105118 )
106119 actor.start(state, handle_message)
107120 |> result.nil_error
···124137pub fn has_full_bucket(rate_limiter: Subject(Message)) -> Bool {
125138 actor.call(rate_limiter, HasFullBucket, 10)
126139}
140140+141141+/// Set the current time for testing purposes.
142142+///
143143+pub fn set_now(rate_limiter: Subject(Message), now: Int) -> Nil {
144144+ actor.send(rate_limiter, SetNow(now))
145145+}
+3
src/glimit/registry.gleam
···1313 Subject(Message(id))
14141515/// The rate limiter registry state.
1616+///
1617type State(id) {
1718 State(
1819 /// The maximum number of tokens.
···7980 }
8081 }
8182 }
8383+8284 GetAll(client) -> {
8385 let rate_limiters =
8486 state.registry
···8789 actor.send(client, rate_limiters)
8890 actor.continue(state)
8991 }
9292+9093 Remove(identifier, client) -> {
9194 let registry = state.registry |> dict.delete(identifier)
9295 let state = State(..state, registry: registry)
-2
test/glimit_rate_limiter_test.gleam
···11import gleeunit/should
22import glimit/rate_limiter
3344-// TODO: find a way to mock time so we can test the refilling of the rate limiter.
55-64pub fn rate_limiter_test() {
75 let limiter = case rate_limiter.new(2, 2) {
86 Ok(limiter) -> limiter