test: handle failing ipaddr lookup

This commit is contained in:
Shivam Mishra
2025-10-06 08:27:19 +05:30
parent 3e955b450b
commit 4c6d3376ef

View File

@@ -7,14 +7,6 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
let(:tool) { described_class.new(assistant, custom_tool) } let(:tool) { described_class.new(assistant, custom_tool) }
let(:tool_context) { Struct.new(:state).new({}) } let(:tool_context) { Struct.new(:state).new({}) }
describe '#description' do
it 'returns the custom tool description' do
custom_tool.update!(description: 'Fetches order status from external API')
expect(tool.description).to eq('Fetches order status from external API')
end
end
describe '#active?' do describe '#active?' do
it 'returns true when custom tool is enabled' do it 'returns true when custom tool is enabled' do
custom_tool.update!(enabled: true) custom_tool.update!(enabled: true)
@@ -34,10 +26,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
before do before do
custom_tool.update!( custom_tool.update!(
http_method: 'GET', http_method: 'GET',
endpoint_url: 'https://api.example.com/orders/123', endpoint_url: 'https://example.com/orders/123',
response_template: nil response_template: nil
) )
stub_request(:get, 'https://api.example.com/orders/123') stub_request(:get, 'https://example.com/orders/123')
.to_return(status: 200, body: '{"status": "success"}') .to_return(status: 200, body: '{"status": "success"}')
end end
@@ -45,7 +37,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
result = tool.perform(tool_context) result = tool.perform(tool_context)
expect(result).to eq('{"status": "success"}') expect(result).to eq('{"status": "success"}')
expect(WebMock).to have_requested(:get, 'https://api.example.com/orders/123') expect(WebMock).to have_requested(:get, 'https://example.com/orders/123')
end end
end end
@@ -53,11 +45,11 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
before do before do
custom_tool.update!( custom_tool.update!(
http_method: 'POST', http_method: 'POST',
endpoint_url: 'https://api.example.com/orders', endpoint_url: 'https://example.com/orders',
request_template: '{"order_id": "{{ order_id }}"}', request_template: '{"order_id": "{{ order_id }}"}',
response_template: nil response_template: nil
) )
stub_request(:post, 'https://api.example.com/orders') stub_request(:post, 'https://example.com/orders')
.with(body: '{"order_id": "123"}', headers: { 'Content-Type' => 'application/json' }) .with(body: '{"order_id": "123"}', headers: { 'Content-Type' => 'application/json' })
.to_return(status: 200, body: '{"created": true}') .to_return(status: 200, body: '{"created": true}')
end end
@@ -66,7 +58,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
result = tool.perform(tool_context, order_id: '123') result = tool.perform(tool_context, order_id: '123')
expect(result).to eq('{"created": true}') expect(result).to eq('{"created": true}')
expect(WebMock).to have_requested(:post, 'https://api.example.com/orders') expect(WebMock).to have_requested(:post, 'https://example.com/orders')
.with(body: '{"order_id": "123"}') .with(body: '{"order_id": "123"}')
end end
end end
@@ -74,10 +66,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
context 'with template variables in URL' do context 'with template variables in URL' do
before do before do
custom_tool.update!( custom_tool.update!(
endpoint_url: 'https://api.example.com/orders/{{ order_id }}', endpoint_url: 'https://example.com/orders/{{ order_id }}',
response_template: nil response_template: nil
) )
stub_request(:get, 'https://api.example.com/orders/456') stub_request(:get, 'https://example.com/orders/456')
.to_return(status: 200, body: '{"order_id": "456"}') .to_return(status: 200, body: '{"order_id": "456"}')
end end
@@ -85,7 +77,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
result = tool.perform(tool_context, order_id: '456') result = tool.perform(tool_context, order_id: '456')
expect(result).to eq('{"order_id": "456"}') expect(result).to eq('{"order_id": "456"}')
expect(WebMock).to have_requested(:get, 'https://api.example.com/orders/456') expect(WebMock).to have_requested(:get, 'https://example.com/orders/456')
end end
end end
@@ -94,10 +86,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
custom_tool.update!( custom_tool.update!(
auth_type: 'bearer', auth_type: 'bearer',
auth_config: { 'token' => 'secret_bearer_token' }, auth_config: { 'token' => 'secret_bearer_token' },
endpoint_url: 'https://api.example.com/data', endpoint_url: 'https://example.com/data',
response_template: nil response_template: nil
) )
stub_request(:get, 'https://api.example.com/data') stub_request(:get, 'https://example.com/data')
.with(headers: { 'Authorization' => 'Bearer secret_bearer_token' }) .with(headers: { 'Authorization' => 'Bearer secret_bearer_token' })
.to_return(status: 200, body: '{"authenticated": true}') .to_return(status: 200, body: '{"authenticated": true}')
end end
@@ -106,7 +98,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
result = tool.perform(tool_context) result = tool.perform(tool_context)
expect(result).to eq('{"authenticated": true}') expect(result).to eq('{"authenticated": true}')
expect(WebMock).to have_requested(:get, 'https://api.example.com/data') expect(WebMock).to have_requested(:get, 'https://example.com/data')
.with(headers: { 'Authorization' => 'Bearer secret_bearer_token' }) .with(headers: { 'Authorization' => 'Bearer secret_bearer_token' })
end end
end end
@@ -116,10 +108,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
custom_tool.update!( custom_tool.update!(
auth_type: 'basic', auth_type: 'basic',
auth_config: { 'username' => 'user123', 'password' => 'pass456' }, auth_config: { 'username' => 'user123', 'password' => 'pass456' },
endpoint_url: 'https://api.example.com/data', endpoint_url: 'https://example.com/data',
response_template: nil response_template: nil
) )
stub_request(:get, 'https://api.example.com/data') stub_request(:get, 'https://example.com/data')
.with(basic_auth: %w[user123 pass456]) .with(basic_auth: %w[user123 pass456])
.to_return(status: 200, body: '{"authenticated": true}') .to_return(status: 200, body: '{"authenticated": true}')
end end
@@ -128,7 +120,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
result = tool.perform(tool_context) result = tool.perform(tool_context)
expect(result).to eq('{"authenticated": true}') expect(result).to eq('{"authenticated": true}')
expect(WebMock).to have_requested(:get, 'https://api.example.com/data') expect(WebMock).to have_requested(:get, 'https://example.com/data')
.with(basic_auth: %w[user123 pass456]) .with(basic_auth: %w[user123 pass456])
end end
end end
@@ -138,10 +130,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
custom_tool.update!( custom_tool.update!(
auth_type: 'api_key', auth_type: 'api_key',
auth_config: { 'key' => 'api_key_123', 'location' => 'header', 'name' => 'X-API-Key' }, auth_config: { 'key' => 'api_key_123', 'location' => 'header', 'name' => 'X-API-Key' },
endpoint_url: 'https://api.example.com/data', endpoint_url: 'https://example.com/data',
response_template: nil response_template: nil
) )
stub_request(:get, 'https://api.example.com/data') stub_request(:get, 'https://example.com/data')
.with(headers: { 'X-API-Key' => 'api_key_123' }) .with(headers: { 'X-API-Key' => 'api_key_123' })
.to_return(status: 200, body: '{"authenticated": true}') .to_return(status: 200, body: '{"authenticated": true}')
end end
@@ -150,7 +142,7 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
result = tool.perform(tool_context) result = tool.perform(tool_context)
expect(result).to eq('{"authenticated": true}') expect(result).to eq('{"authenticated": true}')
expect(WebMock).to have_requested(:get, 'https://api.example.com/data') expect(WebMock).to have_requested(:get, 'https://example.com/data')
.with(headers: { 'X-API-Key' => 'api_key_123' }) .with(headers: { 'X-API-Key' => 'api_key_123' })
end end
end end
@@ -158,10 +150,10 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
context 'with response template' do context 'with response template' do
before do before do
custom_tool.update!( custom_tool.update!(
endpoint_url: 'https://api.example.com/orders/123', endpoint_url: 'https://example.com/orders/123',
response_template: 'Order status: {{ response.status }}, ID: {{ response.order_id }}' response_template: 'Order status: {{ response.status }}, ID: {{ response.order_id }}'
) )
stub_request(:get, 'https://api.example.com/orders/123') stub_request(:get, 'https://example.com/orders/123')
.to_return(status: 200, body: '{"status": "shipped", "order_id": "123"}') .to_return(status: 200, body: '{"status": "shipped", "order_id": "123"}')
end end
@@ -174,8 +166,8 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
context 'when handling errors' do context 'when handling errors' do
it 'returns generic error message on network failure' do it 'returns generic error message on network failure' do
custom_tool.update!(endpoint_url: 'https://api.example.com/data') custom_tool.update!(endpoint_url: 'https://example.com/data')
stub_request(:get, 'https://api.example.com/data').to_raise(SocketError.new('Failed to connect')) stub_request(:get, 'https://example.com/data').to_raise(SocketError.new('Failed to connect'))
result = tool.perform(tool_context) result = tool.perform(tool_context)
@@ -183,8 +175,8 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
end end
it 'returns generic error message on timeout' do it 'returns generic error message on timeout' do
custom_tool.update!(endpoint_url: 'https://api.example.com/data') custom_tool.update!(endpoint_url: 'https://example.com/data')
stub_request(:get, 'https://api.example.com/data').to_timeout stub_request(:get, 'https://example.com/data').to_timeout
result = tool.perform(tool_context) result = tool.perform(tool_context)
@@ -192,8 +184,8 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
end end
it 'returns generic error message on HTTP 404' do it 'returns generic error message on HTTP 404' do
custom_tool.update!(endpoint_url: 'https://api.example.com/data') custom_tool.update!(endpoint_url: 'https://example.com/data')
stub_request(:get, 'https://api.example.com/data').to_return(status: 404, body: 'Not found') stub_request(:get, 'https://example.com/data').to_return(status: 404, body: 'Not found')
result = tool.perform(tool_context) result = tool.perform(tool_context)
@@ -201,8 +193,8 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
end end
it 'returns generic error message on HTTP 500' do it 'returns generic error message on HTTP 500' do
custom_tool.update!(endpoint_url: 'https://api.example.com/data') custom_tool.update!(endpoint_url: 'https://example.com/data')
stub_request(:get, 'https://api.example.com/data').to_return(status: 500, body: 'Server error') stub_request(:get, 'https://example.com/data').to_return(status: 500, body: 'Server error')
result = tool.perform(tool_context) result = tool.perform(tool_context)
@@ -210,8 +202,8 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
end end
it 'logs error details' do it 'logs error details' do
custom_tool.update!(endpoint_url: 'https://api.example.com/data') custom_tool.update!(endpoint_url: 'https://example.com/data')
stub_request(:get, 'https://api.example.com/data').to_raise(StandardError.new('Test error')) stub_request(:get, 'https://example.com/data').to_raise(StandardError.new('Test error'))
expect(Rails.logger).to receive(:error).with(/HttpTool execution error.*Test error/) expect(Rails.logger).to receive(:error).with(/HttpTool execution error.*Test error/)
@@ -223,14 +215,14 @@ RSpec.describe Captain::Tools::HttpTool, type: :model do
it 'correctly integrates URL rendering, body rendering, auth, and response formatting' do it 'correctly integrates URL rendering, body rendering, auth, and response formatting' do
custom_tool.update!( custom_tool.update!(
http_method: 'POST', http_method: 'POST',
endpoint_url: 'https://api.example.com/users/{{ user_id }}/orders', endpoint_url: 'https://example.com/users/{{ user_id }}/orders',
request_template: '{"product": "{{ product }}", "quantity": {{ quantity }}}', request_template: '{"product": "{{ product }}", "quantity": {{ quantity }}}',
auth_type: 'bearer', auth_type: 'bearer',
auth_config: { 'token' => 'integration_token' }, auth_config: { 'token' => 'integration_token' },
response_template: 'Created order #{{ response.order_number }} for {{ response.product }}' response_template: 'Created order #{{ response.order_number }} for {{ response.product }}'
) )
stub_request(:post, 'https://api.example.com/users/42/orders') stub_request(:post, 'https://example.com/users/42/orders')
.with( .with(
body: '{"product": "Widget", "quantity": 5}', body: '{"product": "Widget", "quantity": 5}',
headers: { headers: {