feat(backup-monitor): implement PayloadBuilder with tests

This commit is contained in:
jared 2026-05-07 11:16:40 -04:00
parent 3cbd04fe72
commit c611b2e82a
2 changed files with 78 additions and 0 deletions

View File

@ -56,6 +56,33 @@ class ByteFormatter
end end
class PayloadBuilder class PayloadBuilder
VALID_STATUSES = %w[success failure skipped].freeze
def initialize(options)
@options = options
end
def build
validate!
{
timestamp: Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ'),
machine: @options[:machine],
destination: @options[:destination],
status: @options[:status],
bytes_transferred: ByteFormatter.format(@options[:bytes]),
snapshot_id: @options[:snapshot],
log_path: @options[:log_path],
notes: @options[:notes]
}.compact
end
private
def validate!
return if VALID_STATUSES.include?(@options[:status])
raise ArgumentError, "status must be one of: #{VALID_STATUSES.join(', ')}"
end
end end
class WebhookClient class WebhookClient

View File

@ -29,3 +29,54 @@ class ByteFormatterTest < Minitest::Test
assert_equal '1.00 GB', ByteFormatter.format('1073741824') assert_equal '1.00 GB', ByteFormatter.format('1073741824')
end end
end end
class PayloadBuilderTest < Minitest::Test
def base_options
{ machine: 'desktop', destination: 'synology', status: 'success' }
end
def test_builds_required_fields
payload = PayloadBuilder.new(base_options).build
assert_equal 'desktop', payload[:machine]
assert_equal 'synology', payload[:destination]
assert_equal 'success', payload[:status]
assert_match(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\z/, payload[:timestamp])
end
def test_formats_bytes_to_human_readable
payload = PayloadBuilder.new(base_options.merge(bytes: 1_073_741_824)).build
assert_equal '1.00 GB', payload[:bytes_transferred]
end
def test_omits_nil_optional_fields
payload = PayloadBuilder.new(base_options).build
refute payload.key?(:bytes_transferred)
refute payload.key?(:snapshot_id)
refute payload.key?(:log_path)
refute payload.key?(:notes)
end
def test_includes_all_optional_fields_when_present
opts = base_options.merge(
bytes: 1_048_576,
snapshot: 'abc12345',
log_path: '/home/jared/.local/log/restic/2026-05-07.log',
notes: 'snapshot abc12345 saved'
)
payload = PayloadBuilder.new(opts).build
assert_equal '1.00 MB', payload[:bytes_transferred]
assert_equal 'abc12345', payload[:snapshot_id]
assert_equal '/home/jared/.local/log/restic/2026-05-07.log', payload[:log_path]
assert_equal 'snapshot abc12345 saved', payload[:notes]
end
def test_raises_on_invalid_status
assert_raises(ArgumentError) { PayloadBuilder.new(base_options.merge(status: 'unknown')).build }
end
def test_all_valid_statuses_accepted
%w[success failure skipped].each do |s|
assert PayloadBuilder.new(base_options.merge(status: s)).build
end
end
end