Skip to content

Commit 0b9af48

Browse files
committed
fix: refuse an unknown operation when reading reminders
unschedule already refused an operation the actor does not declare, but reminder and reminders did not. A typo returned nil and an empty array, so a caller asking whether an alarm was armed got told no rather than told it had asked the wrong question. Both now raise the UnknownMessage that schedule and unschedule raise. Found by auditing the Ruby and JavaScript surfaces against each other: the JavaScript reader already validated, and this side did not.
1 parent 47c44e2 commit 0b9af48

3 files changed

Lines changed: 26 additions & 2 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## Unreleased
44

5-
- Refuse an unknown operation in `unschedule` and `unschedule_all`. `schedule`
5+
- Refuse an unknown operation in `reminder`, `reminders`, `unschedule`, and
6+
`unschedule_all`. `schedule`
67
already raised `UnknownMessage` for one, so a typo cancelled nothing quietly
78
and left a recurring reminder running.
89
- Add reminder cancellation. `unschedule` removes one reminder by operation and

‎lib/solid_objects/actor.rb‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,13 @@ def unschedule_all(operation)
293293
def reminder(operation_or_handle, key: nil)
294294
return reminder_view[handle_name(operation_or_handle, key:)] if operation_or_handle.is_a?(Hash)
295295

296+
validated_reminder_operation(operation_or_handle)
296297
reminder_view[reminder_name(operation: operation_or_handle, key: validated_reminder_key(key))]
297298
end
298299

299300
# @rbs (Symbol | String) -> Array[ReminderStatus]
300301
def reminders(operation)
301-
wanted = operation.to_s
302+
wanted = validated_reminder_operation(operation)
302303
reminder_view.each_value.select { |status| status.operation == wanted }
303304
end
304305

‎test/integration/reminder_cancellation_test.rb‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ def convert_then_raise
3838
raise "turn failed"
3939
end
4040

41+
def read_unknown
42+
reminder(:no_such_operation)
43+
end
44+
45+
def list_unknown
46+
reminders(:no_such_operation)
47+
end
48+
4149
def cancel_unknown
4250
unschedule(:no_such_operation)
4351
end
@@ -283,6 +291,20 @@ def state_of(actor_type)
283291
assert_empty reminders_for("cancel-trial")
284292
end
285293

294+
test "an unknown operation is refused when reading rather than reported absent" do
295+
SolidObjects.configuration.max_attempts = 1
296+
reference = TrialActor.ref("alice")
297+
reference.async.start_trial
298+
drain
299+
reference.async.read_unknown
300+
reference.async.list_unknown
301+
drain
302+
303+
assert_equal 2, SolidObjects::DeadLetter.where(actor_type: "cancel-trial").count
304+
assert_equal [ "SolidObjects::UnknownMessage" ],
305+
SolidObjects::DeadLetter.where(actor_type: "cancel-trial").distinct.pluck(:exception_class)
306+
end
307+
286308
test "an unknown operation is refused rather than cancelling nothing" do
287309
SolidObjects.configuration.max_attempts = 1
288310
reference = TrialActor.ref("alice")

0 commit comments

Comments
 (0)