Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Http Status agent #1209

Merged
merged 1 commit into from
Feb 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/concerns/web_request_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ def faraday

builder.headers[:user_agent] = user_agent

builder.use FaradayMiddleware::FollowRedirects
unless boolify(interpolated['disable_redirect_follow'])
builder.use FaradayMiddleware::FollowRedirects
end
builder.request :url_encoded

if boolify(interpolated['disable_url_encoding'])
Expand Down
81 changes: 81 additions & 0 deletions app/models/agents/http_status_agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module Agents

class HttpStatusAgent < Agent

include WebRequestConcern
include FormConfigurable

can_dry_run!
can_order_created_events!

default_schedule "every_12h"

form_configurable :url
form_configurable :disable_redirect_follow, type: :array, values: ['true', 'false']

description <<-MD
The HttpStatusAgent will check a url and emit the resulting HTTP status code.

Specify a `Url` and the Http Status Agent will produce an event with the http status code.

The `disable redirect follow` option causes the Agent to not follow HTTP redirects. For example, setting this to `true` will cause an agent that receives a 301 redirect to `http://yahoo.com` to return a status of 301 instead of following the redirect and returning 200.
MD

event_description <<-MD
Events will have the following fields:

{
"url": "...",
"status": "..."
}
MD

def working?
memory['last_status'].to_i > 0
end

def default_options
{
'url' => "http://google.com",
'disable_redirect_follow' => "true",
}
end

def validate_options
errors.add(:base, "a url must be specified") unless options['url'].present?
end

def check
check_this_url interpolated[:url]
end

def receive(incoming_events)
incoming_events.each do |event|
interpolate_with(event) do
check_this_url interpolated[:url]
end
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cantino Am I making some dumb mistake here?

I thought that I could allow this agent to receive events from other agents, and using "interpolated" would let the event data flow in as options?

I have an agent called "I want urls checked" that passes events like { url: 'http://' } and a HttpStatusAgent called "I check urls" that expect these events.

But it doesn't seem to work... but I swear this worked a couple weeks ago when I switched to interpolated.

huginn

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @darrencauthon. Is your url option set to { url }? You'd need to do that to run the Liquid code to interpolate the url key from the event.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cantino Argh, you were right... I know I was doing something silly. Just had to set the url to {{url}}

end
end

private

def check_this_url(url)
if result = ping(url)
create_event payload: { 'url' => url, 'status' => result.status.to_s, 'response_received' => true }
memory['last_status'] = result.status.to_s
else
create_event payload: { 'url' => url, 'response_received' => false }
memory['last_status'] = nil
end
end

def ping(url)
result = faraday.get url
result.status > 0 ? result : nil
rescue
nil
end

end

end
260 changes: 260 additions & 0 deletions spec/controllers/http_status_agent_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
require 'rails_helper'

describe 'HttpStatusAgent' do

let(:agent) do
Agents::HttpStatusAgent.new(:name => SecureRandom.uuid, :options => valid_params).tap do |a|
a.service = services(:generic)
a.user = users(:jane)
a.options['url'] = 'http://google.com'
a.save!

def a.interpolate_with(e, &block)
@the_event = e
block.call
end

def a.interpolated
@the_event.payload
end

def a.create_event event
@the_created_events ||= []
@the_created_events << event
end

def a.the_created_events
@the_created_events || []
end

def a.faraday
@faraday ||= Struct.new(:programmed_responses).new({}).tap do |f|
def f.get url
programmed_responses[url] || raise('invalid url')
end

def f.set url, response, time = nil
sleep(time/1000) if time
programmed_responses[url] = response
end
end
end
end
end

let(:valid_params) { {} }

describe "working" do
it "should be working when the last status is 200" do
agent.memory['last_status'] = '200'
expect(agent.working?).to eq(true)
end

it "should be working when the last status is 304" do
agent.memory['last_status'] = '304'
expect(agent.working?).to eq(true)
end

it "should not be working if the status is 0" do
agent.memory['last_status'] = '0'
expect(agent.working?).to eq(false)
end

it "should not be working if the status is missing" do
agent.memory['last_status'] = nil
expect(agent.working?).to eq(false)
end

it "should not be working if the status is -1" do
agent.memory['last_status'] = '-1'
expect(agent.working?).to eq(false)
end
end

describe "check" do

before do

def agent.interpolated
@interpolated ||= { :url => SecureRandom.uuid }
end

def agent.check_this_url url
@url = url
end

def agent.checked_url
@url
end

end

it "should check the url" do
agent.check
expect(agent.checked_url).to eq(agent.interpolated[:url])
end

end

describe "receive" do

describe "with an event with a successful ping" do

let(:successful_url) { SecureRandom.uuid }

let(:status_code) { 200 }

let(:event_with_a_successful_ping) do
agent.faraday.set(successful_url, Struct.new(:status).new(status_code))
Event.new.tap { |e| e.payload = { url: successful_url } }
end

let(:events) do
[event_with_a_successful_ping]
end

it "should create one event" do
agent.receive events
expect(agent.the_created_events.count).to eq(1)
end

it "should note that the successful response succeeded" do
agent.receive events
expect(agent.the_created_events[0][:payload]['response_received']).to eq(true)
end

it "should return the status code" do
agent.receive events
expect(agent.the_created_events[0][:payload]['status']).to eq('200')
end

it "should remember the status" do
agent.receive events
expect(agent.memory['last_status']).to eq('200')
end

describe "but the status code is not 200" do
let(:status_code) { 500 }

it "should return the status code" do
agent.receive events
expect(agent.the_created_events[0][:payload]['status']).to eq('500')
end

it "should remember the status" do
agent.receive events
expect(agent.memory['last_status']).to eq('500')
end
end

it "should return the original url" do
agent.receive events
expect(agent.the_created_events[0][:payload]['url']).to eq(successful_url)
end

describe "but the ping returns a status code of 0" do

let(:event_with_a_successful_ping) do
agent.faraday.set(successful_url, Struct.new(:status).new(0))
Event.new.tap { |e| e.payload = { url: successful_url } }
end

it "should create one event" do
agent.receive events
expect(agent.the_created_events.count).to eq(1)
end

it "should note that no response was received" do
agent.receive events
expect(agent.the_created_events[0][:payload]['response_received']).to eq(false)
end

it "should return the original url" do
agent.receive events
expect(agent.the_created_events[0][:payload]['url']).to eq(successful_url)
end

it "should remember no status" do
agent.memory['last_status'] = '200'
agent.receive events
expect(agent.memory['last_status']).to be_nil
end

end

describe "but the ping returns a status code of -1" do

let(:event_with_a_successful_ping) do
agent.faraday.set(successful_url, Struct.new(:status).new(-1))
Event.new.tap { |e| e.payload = { url: successful_url } }
end

it "should create one event" do
agent.receive events
expect(agent.the_created_events.count).to eq(1)
end

it "should note that no response was received" do
agent.receive events
expect(agent.the_created_events[0][:payload]['response_received']).to eq(false)
end

it "should return the original url" do
agent.receive events
expect(agent.the_created_events[0][:payload]['url']).to eq(successful_url)
end

end

describe "and with one event with a failing ping" do

let(:failing_url) { SecureRandom.uuid }
let(:event_with_a_failing_ping) { Event.new.tap { |e| e.payload = { url: failing_url } } }

let(:events) do
[event_with_a_successful_ping, event_with_a_failing_ping]
end

it "should create two events" do
agent.receive events
expect(agent.the_created_events.count).to eq(2)
end

it "should note that the failed response failed" do
agent.receive events
expect(agent.the_created_events[1][:payload]['response_received']).to eq(false)
end

it "should note that the successful response succeeded" do
agent.receive events
expect(agent.the_created_events[0][:payload]['response_received']).to eq(true)
end

it "should return the original url on both events" do
agent.receive events
expect(agent.the_created_events[0][:payload]['url']).to eq(successful_url)
expect(agent.the_created_events[1][:payload]['url']).to eq(failing_url)
end

end

end

describe "validations" do
before do
expect(agent).to be_valid
end

it "should validate url" do
agent.options['url'] = ""
expect(agent).not_to be_valid

agent.options['url'] = "http://www.google.com"
expect(agent).to be_valid
end
end

end


end
11 changes: 11 additions & 0 deletions spec/support/shared_examples/web_request_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,17 @@
agent.options['disable_url_encoding'] = 'true'
expect(agent.faraday.options.params_encoder).to eq(WebRequestConcern::DoNotEncoder)
end

describe "redirect follow" do
it "should use FollowRedirects by default" do
expect(agent.faraday.builder.handlers).to include(FaradayMiddleware::FollowRedirects)
end

it "should not use FollowRedirects when disabled" do
agent.options['disable_redirect_follow'] = true
expect(agent.faraday.builder.handlers).not_to include(FaradayMiddleware::FollowRedirects)
end
end
end

describe WebRequestConcern::DoNotEncoder do
Expand Down