feat(backup-monitor): implement WebhookClient with injected HTTP adapter and tests
This commit is contained in:
parent
c611b2e82a
commit
3e49704bdb
|
|
@ -86,6 +86,32 @@ class PayloadBuilder
|
|||
end
|
||||
|
||||
class WebhookClient
|
||||
def initialize(base_url:, auth_token:, http_adapter: Net::HTTP)
|
||||
@base_url = base_url
|
||||
@auth_token = auth_token
|
||||
@http_adapter = http_adapter
|
||||
end
|
||||
|
||||
def post(payload)
|
||||
uri = URI("#{@base_url}/webhook/backup-notify")
|
||||
request = build_request(uri, payload)
|
||||
|
||||
response = @http_adapter.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
||||
http.request(request)
|
||||
end
|
||||
|
||||
raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_request(uri, payload)
|
||||
req = Net::HTTP::Post.new(uri)
|
||||
req['Content-Type'] = 'application/json'
|
||||
req['Authorization'] = "Bearer #{@auth_token}"
|
||||
req.body = JSON.generate(payload)
|
||||
req
|
||||
end
|
||||
end
|
||||
|
||||
class BackupNotifier
|
||||
|
|
|
|||
|
|
@ -80,3 +80,59 @@ class PayloadBuilderTest < Minitest::Test
|
|||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue