Skip to content

Commit

Permalink
feat: Dynamically retrieve pacts for a given provider
Browse files Browse the repository at this point in the history
  • Loading branch information
rashiagarwal committed May 12, 2018
1 parent 233d860 commit 5aca966
Show file tree
Hide file tree
Showing 11 changed files with 803 additions and 76 deletions.
76 changes: 76 additions & 0 deletions lib/pact/hal/entity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
require 'uri'
require 'delegate'
require 'pact/hal/link'

module Pact
module Hal
class Entity
def initialize(data, http_client, response = nil)
@data = data
@links = @data.fetch("_links", {})
@client = http_client
@response = response
end

def get(key, *args)
_link(key).get(*args)
end

def post(key, *args)
_link(key).post(*args)
end

def put(key, *args)
_link(key).put(*args)
end

def can?(key)
@links.key? key.to_s
end

def follow(key, http_method, *args)
Link.new(@links[key].merge(method: http_method), @client).run(*args)
end

def _link(key)
if @links[key]
Link.new(@links[key], @client)
else
nil
end
end

def success?
true
end

def response
@response
end

def fetch(key)
@links[key]
end

def method_missing(method_name, *args, &block)
if @data.key?(method_name.to_s)
@data[method_name.to_s]
elsif @links.key?(method_name)
Link.new(@links[method_name], @client).run(*args)
else
super
end
end

def respond_to_missing?(method_name, include_private = false)
@data.key?(method_name) || @links.key?(method_name)
end
end

class ErrorEntity < Entity
def success?
false
end
end
end
end
64 changes: 64 additions & 0 deletions lib/pact/hal/http_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require 'pact/retry'

module Pact
module Hal
class HttpClient
attr_accessor :username, :password

def initialize options
@username = options[:username]
@password = options[:password]
end

def get href, params = {}
uri = URI(href)
perform_request(create_request(uri, 'Get'), uri)
end

def put href, body = nil
uri = URI(href)
perform_request(create_request(uri, 'Put', body), uri)
end

def post href, body = nil
uri = URI(href)
perform_request(create_request(uri, 'Post', body), uri)
end

def create_request uri, http_method, body = nil
path = uri.path.size == 0 ? "/" : uri.path
request = Net::HTTP.const_get(http_method).new(path)
request['Content-Type'] = "application/json"
request['Accept'] = "application/hal+json"
request.body = body if body
request.basic_auth username, password if username
request
end

def perform_request request, uri
options = {:use_ssl => uri.scheme == 'https'}
response = Retry.until_true do
Net::HTTP.start(uri.host, uri.port, :ENV, options) do |http|
http.request request
end
end
Response.new(response)
end

class Response < SimpleDelegator
def body
bod = __getobj__().body
if bod && bod != ''
JSON.parse(bod)
else
nil
end
end

def success?
__getobj__().code.start_with?("2")
end
end
end
end
end
65 changes: 65 additions & 0 deletions lib/pact/hal/link.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require 'uri'
require 'delegate'

module Pact
module Hal
class Link
attr_reader :request_method, :href

def initialize(attrs, http_client)
@attrs = attrs
@request_method = attrs.fetch(:method, :get).to_sym
@href = attrs.fetch('href')
@http_client = http_client
end

def run(payload = nil)
response = case request_method
when :get
get(payload)
when :put
put(payload)
when :post
post(payload)
end
end

def get(payload = {})
wrap_response(@http_client.get(href, payload))
end

def put(payload = nil)
wrap_response(@http_client.put(href, payload ? JSON.dump(payload) : nil))
end

def post(payload = nil)
wrap_response(@http_client.post(href, payload ? JSON.dump(payload) : nil))
end

def expand(params)
expanded_url = expand_url(params, href)
new_attrs = @attrs.merge('href' => expanded_url)
Link.new(new_attrs, @http_client)
end

private

def wrap_response(http_response)
require 'pact/hal/entity' # avoid circular reference
if http_response.success?
Entity.new(http_response.body, @http_client, http_response)
else
ErrorEntity.new(http_response.body, @http_client, http_response)
end
end

def expand_url(params, url)
new_url = url
params.each do | key, value |
new_url = new_url.gsub('{' + key.to_s + '}', value)
end
new_url
end
end
end
end
53 changes: 53 additions & 0 deletions lib/pact/pact_broker/fetch_pacts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require 'pact/hal/entity'
require 'pact/hal/http_client'

module Pact
module PactBroker
class FetchPacts
attr_reader :provider, :tags, :broker_base_url, :basic_auth_options, :http_client, :pact_entity

LATEST_PROVIDER_TAG_RELATION = 'pb:latest-provider-pacts-with-tag'.freeze
LATEST_PROVIDER_RELATION = 'pb:latest-provider-pacts'.freeze
PACTS = 'pacts'.freeze
HREF = 'href'.freeze

def initialize(provider, tags, broker_base_url, basic_auth_options)
@provider = provider
@tags = tags

@http_client = Pact::Hal::HttpClient.new(basic_auth_options)
@response = @http_client.get(broker_base_url)
@pact_entity = Pact::Hal::Entity.new(@response.body, http_client)
end

def self.call(provider, tags = nil, broker_base_url, basic_auth_options)
new(provider, tags, broker_base_url, basic_auth_options).call
end

def call
pact_urls = []
if tags
link = pact_entity._link(LATEST_PROVIDER_TAG_RELATION)
tags.each do |tag|
link_by_tag = link.expand(provider: provider, tag: tag).get
get_pact_urls(link_by_tag, pact_urls)
end
else
link = pact_entity._link(LATEST_PROVIDER_RELATION)
link_by_provider = link.expand(provider: provider).get
get_pact_urls(link_by_provider, pact_urls)
end
pact_urls
end

private

def get_pact_urls(link_by_provider, pact_urls)
pacts = link_by_provider.fetch(PACTS)
pacts.each do |pact|
pact_urls.push(pact[HREF])
end
end
end
end
end
Loading

0 comments on commit 5aca966

Please sign in to comment.