Skip to content

Commit a59e46e

Browse files
committed
Started work on webhooks
1 parent 56d9ae5 commit a59e46e

File tree

6 files changed

+208
-0
lines changed

6 files changed

+208
-0
lines changed
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Sequel.migration do
2+
change do
3+
create_table(:webhooks) do
4+
primary_key :id
5+
String :method, null: false
6+
String :url, null: false
7+
String :body
8+
foreign_key :consumer_id, :pacticipants, null: false
9+
foreign_key :provider_id, :pacticipants, null: false
10+
end
11+
12+
create_table(:webhooks_headers) do
13+
String :name, null: false
14+
String :value
15+
foreign_key :webhook_id, :webhooks, null: false
16+
primary_key [:webhook_id, :name], :name=>:webhooks_headers_pk
17+
end
18+
end
19+
end

lib/pact_broker/models/webhook.rb

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module PactBroker
2+
3+
module Models
4+
5+
class Webhook
6+
attr_accessor :id, :consumer_id, :provider_id, :request
7+
end
8+
9+
class WebhookRequest
10+
attr_accessor :method, :url, :headers, :body
11+
12+
def execute
13+
#TODO make it work with https
14+
#TODO validation of method
15+
req = http_request
16+
17+
headers.each do | header |
18+
req[header.name] = header.value
19+
end
20+
req.body = body
21+
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
22+
http.request req
23+
end
24+
25+
end
26+
27+
private
28+
29+
def http_request
30+
Net::HTTP.const_get(method.capitalize).new(uri)
31+
end
32+
33+
def uri
34+
URI(url)
35+
end
36+
end
37+
38+
class WebhookRequestHeader
39+
attr_accessor :id, :name, :value
40+
end
41+
42+
end
43+
44+
end
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require 'pact_broker/models/webhook_request_header'
2+
require 'pact_broker/logging'
3+
4+
module PactBroker
5+
6+
module Models
7+
8+
class WebhookRequestError < StandardError; end
9+
10+
class WebhookRequest
11+
12+
include PactBroker::Logging
13+
14+
attr_accessor :method, :url, :headers, :body
15+
16+
def initialize attributes = {}
17+
@method = attributes.fetch(:method)
18+
@url = attributes.fetch(:url)
19+
@headers = attributes[:headers]
20+
@body = attributes[:body]
21+
end
22+
23+
def execute
24+
#TODO make it work with https
25+
#TODO validation of method
26+
req = http_request
27+
28+
headers.each do | header |
29+
req[header.name] = header.value
30+
end
31+
req.body = body
32+
33+
logger.info "Making webhook request #{to_s}"
34+
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
35+
http.request req
36+
end
37+
38+
logger.info "Received response status=#{response.code} body=#{response.body}"
39+
40+
if Net::HTTPOK === response
41+
true
42+
else
43+
raise WebhookRequestError.new("status=#{response.code} body=#{response.body}")
44+
end
45+
46+
end
47+
48+
private
49+
50+
def to_s
51+
"#{method.upcase} #{url}, headers=#{headers}, body=#{body}"
52+
end
53+
54+
def http_request
55+
Net::HTTP.const_get(method.capitalize).new(url)
56+
end
57+
58+
def uri
59+
URI(url)
60+
end
61+
end
62+
63+
end
64+
65+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module PactBroker
2+
module Models
3+
class WebhookRequestHeader
4+
5+
attr_accessor :name, :value
6+
7+
def initialize name, value
8+
@name = name
9+
@value = value
10+
end
11+
end
12+
end
13+
end

pact_broker.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ Gem::Specification.new do |gem|
3838
gem.add_development_dependency 'fakefs', '~>0.4'
3939
gem.add_development_dependency 'rspec-fire', '~>1.2.0'
4040
gem.add_development_dependency 'mysql2', '~>0.3.15'
41+
gem.add_development_dependency 'webmock'
4142

4243
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
require 'spec_helper'
2+
require 'pact_broker/models/webhook_request'
3+
require 'webmock/rspec'
4+
5+
module PactBroker
6+
7+
module Models
8+
9+
describe WebhookRequest do
10+
11+
subject { WebhookRequest.new(method: 'POST',
12+
url: 'http://example.org/hook',
13+
headers: [WebhookRequestHeader.new('Content-type', 'text/plain')],
14+
body: 'body')}
15+
16+
describe "execute" do
17+
18+
let!(:http_request) do
19+
stub_request(:post, "http://example.org/hook").
20+
with(:headers => {'Content-Type'=>'text/plain'}, :body => 'body').
21+
to_return(:status => 200, :body => "respbod", :headers => {})
22+
end
23+
24+
it "executes the configured request" do
25+
subject.execute
26+
expect(http_request).to have_been_made
27+
end
28+
29+
it "logs the request" do
30+
allow(PactBroker.logger).to receive(:info)
31+
expect(PactBroker.logger).to receive(:info).with(/POST.*example.*text.*body/)
32+
subject.execute
33+
end
34+
35+
it "logs the response" do
36+
allow(PactBroker.logger).to receive(:info)
37+
expect(PactBroker.logger).to receive(:info).with(/response.*200.*respbod/)
38+
subject.execute
39+
end
40+
41+
context "when the request is successful" do
42+
it "returns true" do
43+
expect(subject.execute).to be true
44+
end
45+
end
46+
47+
context "when the request is not successful" do
48+
49+
let!(:http_request) do
50+
stub_request(:post, "http://example.org/hook").
51+
with(:headers => {'Content-Type'=>'text/plain'}, :body => 'body').
52+
to_return(:status => 500, :body => "An error")
53+
end
54+
55+
it "raises an error" do
56+
expect { subject.execute }.to raise_error WebhookRequestError, /500.*An error/
57+
end
58+
end
59+
60+
end
61+
62+
end
63+
64+
end
65+
66+
end

0 commit comments

Comments
 (0)