Skip to content

Commit

Permalink
feat: allow webhook with optional consumer and/or provider to be crea…
Browse files Browse the repository at this point in the history
…ted by posting to /webhooks
  • Loading branch information
bethesque committed Jun 16, 2018
1 parent e60460e commit b15ba85
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 5 deletions.
56 changes: 55 additions & 1 deletion lib/pact_broker/api/resources/all_webhooks.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'pact_broker/services'
require 'pact_broker/api/resources/base_resource'
require 'pact_broker/api/decorators/webhooks_decorator'
require 'pact_broker/api/decorators/webhook_decorator'
require 'pact_broker/api/contracts/webhook_contract'

module PactBroker
module Api
Expand All @@ -11,17 +13,69 @@ def content_types_provided
[["application/hal+json", :to_json]]
end

def content_types_accepted
[["application/json", :from_json]]
end

def allowed_methods
["GET"]
["GET", "POST"]
end

def create_path
webhook_url next_uuid, base_url
end

def post_is_create?
true
end

def malformed_request?
if request.post?
return invalid_json? || validation_errors?(webhook)
end
false
end

def to_json
Decorators::WebhooksDecorator.new(webhooks).to_json(user_options: decorator_context(resource_title: "Webhooks"))
end

def from_json
saved_webhook = webhook_service.create next_uuid, webhook, consumer, provider
response.body = Decorators::WebhookDecorator.new(saved_webhook).to_json(user_options: { base_url: base_url })
end

private

def validation_errors? webhook
errors = webhook_service.errors(webhook)

unless errors.empty?
set_json_validation_error_messages(errors.messages)
end

!errors.empty?
end

def consumer
webhook.consumer ? pacticipant_service.find_pacticipant_by_name(webhook.consumer.name) : nil
end

def provider
webhook.provider ? pacticipant_service.find_pacticipant_by_name(webhook.provider.name) : nil
end

def webhooks
webhook_service.find_all
end

def webhook
@webhook ||= Decorators::WebhookDecorator.new(PactBroker::Domain::Webhook.new).from_json(request_body)
end

def next_uuid
@next_uuid ||= webhook_service.next_uuid
end
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/pact_broker/domain/webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ def description
"A webhook for the pact between #{consumer.name} and #{provider.name}"
elsif provider
"A webhook for all pacts with provider #{provider.name}"
else
elsif consumer
"A webhook for all pacts with consumer #{consumer.name}"
else
"A webhook for all pacts"
end
end

Expand Down
28 changes: 25 additions & 3 deletions spec/features/create_webhook_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
}
end

subject { post path, webhook_json, headers }
subject { post(path, webhook_json, headers) }

context "for a consumer and provider" do
let(:path) { "/webhooks/provider/Some%20Provider/consumer/Some%20Consumer" }
Expand Down Expand Up @@ -75,7 +75,11 @@
end

context "for a provider" do
let(:path) { "/webhooks/provider/Some%20Provider" }
let(:path) { "/webhooks" }

before do
webhook_hash[:provider] = { name: "Some Provider" }
end

it "returns a 201 response" do
subject
Expand All @@ -90,7 +94,10 @@
end

context "for a consumer" do
let(:path) { "/webhooks/consumer/Some%20Consumer" }
let(:path) { "/webhooks" }
before do
webhook_hash[:consumer] = { name: "Some Consumer" }
end

it "returns a 201 response" do
subject
Expand All @@ -103,4 +110,19 @@
expect(PactBroker::Webhooks::Webhook.first.provider).to be nil
end
end

context "with no consumer or provider" do
let(:path) { "/webhooks" }

it "returns a 201 response" do
subject
expect(last_response.status).to be 201
end

it "creates a webhook without a provider" do
subject
expect(PactBroker::Webhooks::Webhook.first.consumer).to be nil
expect(PactBroker::Webhooks::Webhook.first.provider).to be nil
end
end
end
110 changes: 110 additions & 0 deletions spec/lib/pact_broker/api/resources/all_webhooks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,116 @@ module Resources

describe AllWebhooks do

let(:webhook_service) { PactBroker::Webhooks::Service }
let(:uuid) { '1483234k24DKFGJ45K' }
let(:path) { "/webhooks" }
let(:headers) { {'CONTENT_TYPE' => 'application/json'} }
let(:webhook) { double('webhook', consumer: parsed_consumer, provider: parsed_provider) }
let(:parsed_provider) { instance_double(PactBroker::Domain::Pacticipant, name: "Some Provider") }
let(:parsed_consumer) { instance_double(PactBroker::Domain::Pacticipant, name: "Some Consumer") }
let(:consumer) { double('consumer', name: "Some Consumer") }
let(:provider) { double('provider', name: "Some Provider") }
let(:saved_webhook) { double('saved_webhook')}
let(:webhook_decorator) { instance_double(Decorators::WebhookDecorator, from_json: webhook) }

before do
allow(PactBroker::Pacticipants::Service).to receive(:find_pacticipant_by_name).with("Some Provider").and_return(provider)
allow(PactBroker::Pacticipants::Service).to receive(:find_pacticipant_by_name).with("Some Consumer").and_return(consumer)
allow(Decorators::WebhookDecorator).to receive(:new).and_return(webhook_decorator)
end

describe "POST" do
let(:webhook_json) do
{
some: 'json'
}.to_json
end

let(:next_uuid) { '123k2nvkkwjrwk34' }
let(:valid) { true }
let(:errors) { double("errors", empty?: valid, messages: ['messages']) }

before do
allow(webhook_service).to receive(:create).and_return(saved_webhook)
allow(webhook_service).to receive(:next_uuid).and_return(next_uuid)
allow(webhook_service).to receive(:errors).and_return(errors)
allow(PactBroker::Domain::Webhook).to receive(:new).and_return(webhook)
end

subject { post path, webhook_json, headers }

context "with malformed JSON" do
let(:webhook_json) { "{" }

it "returns a 400 error" do
subject
expect(last_response.status).to eq 400
end
end

context "with invalid attributes" do

let(:valid) { false }

it "returns a 400" do
subject
expect(last_response.status).to be 400
end

it "returns a HAL JSON content type" do
subject
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
end

it "returns the validation errors" do
subject
expect(JSON.parse(last_response.body, symbolize_names: true)).to eq errors: ['messages']
end

end

context "with valid attributes" do

let(:webhook_response_json) { { some: 'webhook' }.to_json }

before do
allow_any_instance_of(Decorators::WebhookDecorator).to receive(:to_json).and_return(webhook_response_json)
allow(webhook_decorator).to receive(:to_json).and_return(webhook_response_json)
end

it "saves the webhook" do
expect(webhook_service).to receive(:create).with(next_uuid, webhook, consumer, provider)
subject
end

it "returns a 201 response" do
subject
expect(last_response.status).to be 201
end

it "returns the Location header" do
subject
expect(last_response.headers['Location']).to include(next_uuid)
end

it "returns a HAL JSON content type" do
subject
expect(last_response.headers['Content-Type']).to eq 'application/hal+json;charset=utf-8'
end

it "generates the JSON response body" do
expect(Decorators::WebhookDecorator).to receive(:new).with(saved_webhook).and_return(webhook_decorator)
expect(webhook_decorator).to receive(:to_json).with(user_options: { base_url: 'http://example.org' })
subject
end

it "returns the JSON representation of the webhook" do
subject
expect(last_response.body).to eq webhook_response_json
end
end
end

describe "GET" do

subject { get "/webhooks" }
Expand Down
7 changes: 7 additions & 0 deletions spec/lib/pact_broker/domain/webhook_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ module Domain

it { is_expected.to eq "A webhook for all pacts with provider Provider" }
end

context "with neither a consumer nor a provider" do
let(:consumer) { nil }
let(:provider) { nil }

it { is_expected.to eq "A webhook for all pacts" }
end
end

describe "execute" do
Expand Down

0 comments on commit b15ba85

Please sign in to comment.