Skip to content
This repository has been archived by the owner on Dec 5, 2019. It is now read-only.

[WIP] Better Swagger + Legacy testing #165

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ group :samples do
gem 'pry'
gem 'rack'
end

gem 'swagger-core', git: 'foo'
1 change: 1 addition & 0 deletions features/generate/generation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Feature: Contract Generation
}
"""

@legacy
Scenario: Generating a contract using the rake task
Given a directory named "contracts"
When I successfully run `bundle exec rake pacto:generate['tmp/aruba/requests','tmp/aruba/contracts','http://localhost:8000']`
Expand Down
4 changes: 2 additions & 2 deletions features/support/env.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# -*- encoding : utf-8 -*-
require_relative '../../spec/coveralls_helper'
require 'aruba'
require 'aruba/cucumber'
require 'json_spec/cucumber'
require 'aruba/jruby' if RUBY_PLATFORM == 'java'
require 'pacto/test_helper'
require_relative '../../spec/coveralls_helper'
require_relative '../../spec/fixtures_helper'
require_relative '../../spec/pacto/dummy_server'

Pacto.configuration.hide_deprecations = true
Expand Down
5 changes: 3 additions & 2 deletions lib/pacto/actors/from_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ def build_request(contract, values = {})
request_values = (values || {}).dup
if contract.examples?
example = @selector.select(contract.examples, values)
data = contract.request.to_hash
data = {} # contract.request.to_hash
request_values.merge! example_uri_values(contract)
data['method'] = contract.request.http_method
data['uri'] = contract.request.uri(request_values)
data['headers'] = contract.request.headers
data['body'] = example.request.body
data['method'] = contract.request.http_method
Pacto::PactoRequest.new(data)
else
@fallback_actor.build_request contract, values
Expand Down
18 changes: 12 additions & 6 deletions lib/pacto/actors/json_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ module Pacto
module Actors
class JSONGenerator < Actor
def build_request(contract, values = {})
data = contract.request.to_hash
data['uri'] = contract.request.uri(values)
data['body'] = JSON::Generator.generate(data['schema'])
data['method'] = contract.request.http_method
rc = contract.request
data = {}
data['method'] = rc.http_method
data['uri'] = rc.uri(values)
data['headers'] = rc.headers
data['body'] = JSON::Generator.generate(rc.schema)
Pacto::PactoRequest.new(data)
end

def build_response(contract, _values = {})
data = contract.response.to_hash
data['body'] = JSON::Generator.generate(data['schema'])
rc = contract.response
data = {
status: rc.status,
headers: rc.headers,
body: JSON::Generator.generate(rc.schema)
}
Pacto::PactoResponse.new(data)
end
end
Expand Down
9 changes: 7 additions & 2 deletions lib/pacto/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ module CLI
class Main < Thor
include Pacto::CLI::Helpers

desc 'meta_validate [CONTRACTS...]', 'Validates a directory of contract definitions'
def meta_validate(*contracts)
desc 'lint [CONTRACTS...]', 'Validates a directory of contract definitions'
def lint(*contracts)
invalid = []
each_contract(*contracts) do |contract_file|
begin
Expand All @@ -26,6 +26,11 @@ def meta_validate(*contracts)
say 'All contracts successfully meta-validated'
end

desc 'meta_validate [CONTRACTS...]', '[Deprecated] Old alias for lint'
def meta_validate(*contracts)
lint(*contracts)
end

desc 'validate [CONTRACTS...]', 'Validates all contracts in a given directory against a given host'
method_option :host, type: :string, desc: 'Override host in contracts for validation'
def validate(*contracts)
Expand Down
2 changes: 1 addition & 1 deletion lib/pacto/consumer/faraday_driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def execute(req)
response = conn.send(req.method) do |faraday_request|
faraday_request.url(req.uri.path, req.uri.query_values)
faraday_request.headers = req.headers
faraday_request.body = req.body
faraday_request.body = req.raw_body
end

faraday_to_pacto_response response
Expand Down
3 changes: 3 additions & 0 deletions lib/pacto/contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module Pacto
class Contract < Pacto::Dash
include Logger
extend Forwardable

property :id
property :file
Expand All @@ -20,6 +21,8 @@ class Contract < Pacto::Dash
property :consumer, default: proc { Pacto.configuration.default_consumer }
property :provider, default: proc { Pacto.configuration.default_provider }

def_delegators :request, :host, :uri

def initialize(opts)
if opts[:file]
opts[:file] = Addressable::URI.convert_path(File.expand_path(opts[:file])).to_s
Expand Down
23 changes: 17 additions & 6 deletions lib/pacto/core/pacto_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ class PactoRequest
attr_accessor :headers, :body, :method, :uri

def initialize(data)
mash = Hashie::Mash.new data
@headers = mash.headers.nil? ? {} : mash.headers
@body = mash.body
@method = mash[:method]
@uri = mash.uri
data.singleton_class.send(:include, Hashie::Extensions::IndifferentAccess)
@headers = data[:headers].nil? ? {} : data[:headers]
@body = data[:body]
@method = data[:method]
@uri = data[:uri]
normalize
end

Expand All @@ -27,7 +27,7 @@ def to_hash
def to_s
string = Pacto::UI.colorize_method(method)
string << " #{relative_uri}"
string << " with body (#{body.bytesize} bytes)" if body
string << " with body (#{raw_body.bytesize} bytes)" if body
string
end

Expand All @@ -37,6 +37,17 @@ def relative_uri
end
end

def raw_body
return body if body.is_a? String

case content_type
when 'application/json', nil
JSON.dump(body)
else
fail NotImplementedError, "No encoder for #{body.class} to #{content_type}"
end
end

def parsed_body
if body.is_a?(String) && content_type == 'application/json'
JSON.parse(body)
Expand Down
15 changes: 14 additions & 1 deletion lib/pacto/core/pacto_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,23 @@ def to_hash

def to_s
string = "STATUS: #{status}"
string << " with body (#{body.bytesize} bytes)" if body
string << " with body (#{raw_body.bytesize} bytes)" if body
string
end

def raw_body
if content_type == 'application/json'
case body
when String
body
else
JSON.dump(body)
end
else
body.to_s
end
end

def parsed_body
if body.is_a?(String) && content_type == 'application/json'
JSON.parse(body)
Expand Down
8 changes: 6 additions & 2 deletions lib/pacto/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,12 @@ def initialize
@hints = Set.new
end

def hint(name, hint_data)
@hints << Pacto::Generator::Hint.new(hint_data.merge(service_name: name))
def hint(name, request_data)
hint_data = {
service_name: name,
target_file: request_data.delete(:target_file)
}
@hints << Pacto::Generator::Hint.new(hint_data, RequestClause.new(request_data))
end
end
end
Expand Down
12 changes: 8 additions & 4 deletions lib/pacto/generator/hint.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
# -*- encoding : utf-8 -*-
module Pacto
module Generator
class Hint < Pacto::RequestClause
class Hint < Pacto::Dash
extend Forwardable
property :service_name, required: true
property :target_file
attr_reader :request_clause
def_delegators :@request_clause, *RequestClause.instance_methods(false)

def initialize(data)
super
def initialize(data, request_clause)
@request_clause = request_clause
super(data)
self.target_file ||= "#{slugify(service_name)}.json"
self
end

def matches?(pacto_request)
return false if pacto_request.nil?
Pacto::RequestPattern.for(self).matches?(pacto_request)
Pacto::RequestPattern.for(request_clause).matches?(pacto_request)
end

private
Expand Down
5 changes: 3 additions & 2 deletions lib/pacto/request_clause.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ class RequestClause < Pacto::Dash
property :path, default: '/'
property :headers
property :params, default: {}
property :request_pattern_provider, default: Pacto::RequestPattern
attr_accessor :request_pattern_provider

def initialize(definition)
mash = Hashie::Mash.new definition
mash['http_method'] = normalize(mash['http_method'])
@request_pattern_provider = Pacto::RequestPattern
super mash
end

Expand All @@ -27,7 +28,7 @@ def pattern
def uri(values = {})
values ||= {}
uri_template = pattern.uri_template
missing_keys = uri_template.keys - values.keys
missing_keys = (uri_template.keys - values.keys).map(&:to_sym)
values[:scheme] = 'http' if missing_keys.delete(:scheme)
values[:server] = 'localhost' if missing_keys.delete(:server)
logger.warn "Missing keys for building a complete URL: #{missing_keys.inspect}" unless missing_keys.empty?
Expand Down
2 changes: 2 additions & 0 deletions lib/pacto/stubs/uri_pattern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def build_template_uri_pattern(request, strict)
if strict
Addressable::Template.new("#{scheme}://#{host}#{path}")
else
# host = '{server}'
# scheme = '{scheme}'
Addressable::Template.new("#{scheme}://#{host}#{path}{?anyvars*}")
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pacto/stubs/webmock_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def format_body(body)

def strict_details(request)
{}.tap do |details|
details[webmock_params_key(request)] = request.params unless request.params.empty?
details[webmock_params_key(request)] = request.params unless request.params.nil? || request.params.empty?
details[:headers] = request.headers unless request.headers.empty?
end
end
Expand Down
42 changes: 37 additions & 5 deletions lib/pacto/swagger/request_clause.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,43 @@
module Pacto
module Swagger
class RequestClause < Pacto::RequestClause
def initialize(swagger_api_operation, base_data = {})
host = base_data[:host] || swagger_api_operation.host
super base_data.merge(host: host,
http_method: swagger_api_operation.verb,
path: swagger_api_operation.path)
attr_reader :swagger_api_operation
attr_reader :overrides

def initialize(swagger_api_operation, overrides = {})
@swagger_api_operation = swagger_api_operation
@overrides = overrides
@request_pattern_provider = Pacto::RequestPattern
end

def host
@overrides[:host] || swagger_api_operation.host
end

def http_method
swagger_api_operation.verb
end

def path
self[:path] ||= swagger_api_operation.path
end

def headers
h = {}
swagger_api_operation.parameters.each do |parameter|
# Note: Can't use parameter.default because it conflicts w/ Hash#default method!
h[parameter.name] = parameter['default'] if parameter.in == 'header'
end if swagger_api_operation.parameters
h
end

def schema
schema = {}
if swagger_api_operation.parameters
body_param = swagger_api_operation.parameters.find { |p| p.in == 'body' }
schema = body_param.schema if body_param
end
schema
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/pacto/swagger/response_clause.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ def initialize(swagger_response, base_data = {})

super base_data.merge(data)
end

def headers
h = {}
swagger_response.headers.each do |name, metadata|
# Note: Can't use header.default because it conflicts w/ Hash#default method!
h[name] = metadata['default']
end if swagger_response.headers
h
end
end
end
end
11 changes: 6 additions & 5 deletions lib/pacto/swagger_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@
module Pacto
class SwaggerContract < Pacto::Contract
attr_reader :swagger_api_operation
# def_delegators :@swagger_api_operation, :host

def initialize(swagger_api_operation, base_data = {})
def initialize(swagger_api_operation, overrides = {})
@swagger_api_operation = swagger_api_operation
host = base_data.delete(:host) || swagger_api_operation.host
default_response = swagger_api_operation.default_response
request_clause = Pacto::Swagger::RequestClause.new(swagger_api_operation, host: host)
request_clause = Pacto::Swagger::RequestClause.new(swagger_api_operation, overrides.dup)

if default_response.nil?
logger.warn("No response defined for #{swagger_api_operation.full_name}")
logger.warn("No response defined for #{swagger_api_operation.operationId}")
response_clause = Pacto::ResponseClause.new(status: 200)
else
response_clause = Pacto::Swagger::ResponseClause.new(default_response)
end

examples = build_examples(default_response)
super base_data.merge(
overrides.delete(:host)
super overrides.merge(
id: swagger_api_operation.operationId,
name: swagger_api_operation.full_name,
request: request_clause, response: response_clause,
Expand Down
8 changes: 5 additions & 3 deletions lib/pacto/swagger_contract_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ class SwaggerContractFactory
def load_hints(contract_path, host = nil)
app = ::Swagger.load(contract_path)
app.operations.map do |op|
hint_data = {
service_name: op.full_name,
target_file: contract_path
}
request_clause = Pacto::Swagger::RequestClause.new(op, host: host)
Pacto::Generator::Hint.new(request_clause.to_hash.merge(
service_name: op.fetch(:summary)
))
Pacto::Generator::Hint.new(hint_data, request_clause)
end
end

Expand Down
Loading