139 lines
3.8 KiB
Ruby
139 lines
3.8 KiB
Ruby
#!/usr/bin/env ruby
|
|
# frozen_string_literal: true
|
|
|
|
require 'minitest/autorun'
|
|
require_relative 'notify_backup'
|
|
|
|
class ByteFormatterTest < Minitest::Test
|
|
def test_gigabytes
|
|
assert_equal '4.50 GB', ByteFormatter.format(4_831_838_208)
|
|
end
|
|
|
|
def test_megabytes
|
|
assert_equal '823.00 MB', ByteFormatter.format(862_978_048)
|
|
end
|
|
|
|
def test_kilobytes
|
|
assert_equal '12.00 KB', ByteFormatter.format(12_288)
|
|
end
|
|
|
|
def test_bytes_below_one_kb
|
|
assert_equal '512 B', ByteFormatter.format(512)
|
|
end
|
|
|
|
def test_nil_returns_nil
|
|
assert_nil ByteFormatter.format(nil)
|
|
end
|
|
|
|
def test_string_integer_is_coerced
|
|
assert_equal '1.00 GB', ByteFormatter.format('1073741824')
|
|
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
|
|
|
|
# Stub HTTP adapter for WebhookClient tests — replaces Net::HTTP entirely.
|
|
# Sandi Metz: test the interface, inject the dependency, don't touch globals.
|
|
class FakeHttpAdapter
|
|
def initialize(response)
|
|
@response = response
|
|
end
|
|
|
|
def start(_host, _port, use_ssl: false)
|
|
yield FakeHttpSession.new(@response)
|
|
end
|
|
end
|
|
|
|
class FakeHttpSession
|
|
def initialize(response)
|
|
@response = response
|
|
end
|
|
|
|
def request(_req)
|
|
@response
|
|
end
|
|
end
|
|
|
|
class WebhookClientTest < Minitest::Test
|
|
def make_success_response
|
|
res = Net::HTTPSuccess.new('1.1', '200', 'OK')
|
|
res.instance_variable_set(:@read, true)
|
|
res
|
|
end
|
|
|
|
def make_error_response
|
|
res = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
|
|
res.instance_variable_set(:@body, 'something broke')
|
|
res.instance_variable_set(:@read, true)
|
|
res
|
|
end
|
|
|
|
def make_client(response)
|
|
WebhookClient.new(
|
|
base_url: 'https://n8n.example.com',
|
|
auth_token: 'test-token',
|
|
http_adapter: FakeHttpAdapter.new(response)
|
|
)
|
|
end
|
|
|
|
def test_post_succeeds_on_200
|
|
client = make_client(make_success_response)
|
|
client.post({ machine: 'desktop', status: 'success' }) # no error raised
|
|
end
|
|
|
|
def test_post_raises_on_500
|
|
client = make_client(make_error_response)
|
|
err = assert_raises(RuntimeError) { client.post({}) }
|
|
assert_match(/HTTP 500/, err.message)
|
|
end
|
|
end
|