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

Commit

Permalink
Begin using thor
Browse files Browse the repository at this point in the history
  • Loading branch information
maxlinc committed Nov 18, 2014
1 parent 4498654 commit d5302e8
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 92 deletions.
4 changes: 4 additions & 0 deletions bin/pacto
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
require 'pacto/cli'

Pacto::CLI::Main.start
4 changes: 2 additions & 2 deletions features/evolve/existing_services.feature
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ Feature: Existing services journey
When I successfully run `bundle exec rake pacto:meta_validate['contracts']`
Then the stdout should contain exactly:
"""
Validating contracts/www.example.com/service1.json
Validating contracts/www.example.com/service2.json
validated contracts/www.example.com/service1.json
validated contracts/www.example.com/service2.json
All contracts successfully meta-validated
"""
Expand Down
9 changes: 0 additions & 9 deletions features/validate/meta_validation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,6 @@ Feature: Meta-validation
When I successfully run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`
Then the stdout should contain "All contracts successfully meta-validated"

Scenario: Programmatic meta-validation
Given a file named "meta_validate.rb" with:
"""ruby
require 'pacto'
Pacto.validate_contract 'contracts/my_contract.json'
"""
When I successfully run `bundle exec ruby meta_validate.rb`
Then the stdout should contain "Validating contracts/my_contract.json"

# The tests from here down should probably be specs instead of relish

Scenario: Meta-validation of an invalid contract
Expand Down
5 changes: 2 additions & 3 deletions features/validate/validation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ Feature: Validation
When I successfully run `bundle exec rake pacto:validate['http://localhost:8000','tmp/aruba/contracts/simple_contract.json']`
Then the stdout should contain:
""""
Validating contracts in directory tmp/aruba/contracts/simple_contract.json against host http://localhost:8000
simple_contract.json: OK!
Validating contracts against host http://localhost:8000
OK! simple_contract.json
1 valid contract
"""
8 changes: 1 addition & 7 deletions lib/pacto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,10 @@ def contracts_for(request_signature)
contract_registry.contracts_for(request_signature)
end

# @throws Pacto::InvalidContract
def validate_contract(contract)
Pacto::MetaSchema.new.validate contract
puts "Validating #{contract}"
true
rescue InvalidContract => exception
puts 'Investigation errors detected'
exception.errors.each do |error|
puts " Error: #{error}"
end
false
end

def load_contract(contract_path, host, format = :default)
Expand Down
75 changes: 75 additions & 0 deletions lib/pacto/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require 'thor'
require 'pacto'
require 'pacto/cli/helpers'

module Pacto
module CLI
class Main < Thor
include Pacto::CLI::Helpers

desc 'meta_validate [CONTRACTS...]', 'Validates a directory of contract definitions'
def meta_validate(*contracts)
invalid = []
each_contract(*contracts) do |contract_file|
begin
Pacto.validate_contract(contract_file)
say_status :validated, contract_file
rescue InvalidContract => exception
invalid << contract_file
shell.say_status :invalid, contract_file, :red
exception.errors.each do |error|
say set_color(" Error: #{error}", :red)
end
end
end
abort "The following contracts were invalid: #{invalid.join(',')}" unless invalid.empty?
say 'All contracts successfully meta-validated'
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)
host = options[:host]
WebMock.allow_net_connect!
banner = 'Validating contracts'
banner << " against host #{host}" unless host.nil?
say banner

invalid_contracts = []
tested_contracts = []
each_contract(*contracts) do |contract_file|
tested_contracts << contract_file
invalid_contracts << contract_file unless contract_is_valid?(contract_file, host)
end

validation_summary(tested_contracts, invalid_contracts)
end

private

def validation_summary(contracts, invalid_contracts)
if invalid_contracts.empty?
say set_color("#{contracts.size} valid contract#{contracts.size > 1 ? 's' : nil}", :green)
else
abort set_color("#{invalid_contracts.size} of #{contracts.size} failed. Check output for detailed error messages.", :red)
end
end

def contract_is_valid?(contract_file, host)
name = File.split(contract_file).last
contract = Pacto.load_contract(contract_file, host)
investigation = contract.simulate_request

if investigation.successful?
say_status 'OK!', name
true
else
say_status 'FAILED!', name, :red
say set_color(investigation.summary, :red)
say set_color(investigation.to_s, :red)
false
end
end
end
end
end
20 changes: 20 additions & 0 deletions lib/pacto/cli/helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Pacto
module CLI
module Helpers
def each_contract(*contracts)
[*contracts].each do |contract|
if File.file? contract
yield contract
else # Should we assume it's a dir, or also support glob patterns?
contracts = Dir[File.join(contract, '**/*{.json.erb,.json}')]
fail Pacto::UI.colorize("No contracts found in directory #{contract}", :yellow) if contracts.empty?

contracts.sort.each do |contract_file|
yield contract_file
end
end
end
end
end
end
end
74 changes: 15 additions & 59 deletions lib/pacto/rake_task.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
# -*- encoding : utf-8 -*-
require 'pacto'
require 'thor'
require 'pacto/cli'
require 'pacto/cli/helpers'

# FIXME: RakeTask is a huge class, refactor this please
# rubocop:disable ClassLength
module Pacto
class RakeTask
extend Forwardable
include Thor::Actions
include Rake::DSL
include Pacto::CLI::Helpers

def initialize
@exit_with_error = false
@cli = Pacto::CLI::Main.new
end

def run(task, args, opts = {})
Pacto::CLI::Main.new([], opts).public_send(task, *args)
end

def install
Expand All @@ -23,11 +34,9 @@ def install
def validate_task
desc 'Validates all contracts in a given directory against a given host'
task :validate, :host, :dir do |_t, args|
if args.to_a.size < 2
fail Pacto::UI.colorize('USAGE: rake pacto:validate[<host>, <contract_dir>]', :yellow)
end

validate_contracts(args[:host], args[:dir])
opts = args.to_hash
dir = opts.delete :dir
run(:validate, dir, opts)
end
end

Expand All @@ -42,51 +51,13 @@ def generate_task
end
end

# FIXME: meta_validate is a big method =(. Needs refactoring
# rubocop:disable MethodLength
def meta_validate
desc 'Validates a directory of contract definitions'
task :meta_validate, :dir do |_t, args|
if args.to_a.size < 1
fail Pacto::UI.colorize('USAGE: rake pacto:meta_validate[<contract_dir>]', :yellow)
end

each_contract(args[:dir]) do |contract_file|
fail unless Pacto.validate_contract contract_file
end
puts 'All contracts successfully meta-validated'
run(:meta_validate, *args)
end
end

def validate_contracts(host, dir)
WebMock.allow_net_connect!
puts "Validating contracts in directory #{dir} against host #{host}\n\n"

total_failed = 0
contracts = []
each_contract(dir) do |contract_file|
contracts << contract_file
print "#{contract_file.split('/').last}:"
contract = Pacto.load_contract(contract_file, host)
investigation = contract.simulate_request

if investigation.successful?
puts Pacto::UI.colorize(' OK!', :green)
else
@exit_with_error = true
total_failed += 1
puts Pacto::UI.colorize(' FAILED!', :red)
puts Pacto::UI.colorize(investigation.summary, :red)
puts Pacto::UI.colorize(investigation.to_s, :red)
end
end

if @exit_with_error
fail Pacto::UI.colorize("#{total_failed} of #{contracts.size} failed. Check output for detailed error messages.", :red)
else
puts Pacto::UI.colorize("#{contracts.size} valid contract#{contracts.size > 1 ? 's' : nil}", :green)
end
end
# rubocop:enable MethodLength

# FIXME: generate_contracts is a big method =(. Needs refactoring
Expand Down Expand Up @@ -118,21 +89,6 @@ def generate_contracts(input_dir, output_dir, host)
end
end
# rubocop:enable MethodLength

private

def each_contract(dir)
if File.file? dir
yield dir
else
contracts = Dir[File.join(dir, '**/*{.json.erb,.json}')]
fail Pacto::UI.colorize("No contracts found in directory #{dir}", :yellow) if contracts.empty?

contracts.sort.each do |contract_file|
yield contract_file
end
end
end
end
end
# rubocop:enable ClassLength
Expand Down
15 changes: 3 additions & 12 deletions spec/unit/pacto/pacto_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,17 @@ def mock_investigation(errors)

describe '.validate_contract' do
context 'valid' do
it 'displays a success message and return true' do
it 'returns true' do
mock_investigation []
success = described_class.validate_contract 'my_contract.json'
expect(output).to eq 'Validating my_contract.json'
expect(success).to be true
end
end

context 'invalid' do
it 'displays one error messages and return false' do
it 'raises an InvalidContract error' do
mock_investigation ['Error 1']
success = described_class.validate_contract 'my_contract.json'
expect(output).to match(/error/)
expect(success).to be_falsey
end

it 'displays several error messages and return false' do
mock_investigation ['Error 1', 'Error 2']
success = described_class.validate_contract 'my_contract.json'
expect(success).to be_falsey
expect { described_class.validate_contract 'my_contract.json' }.to raise_error(InvalidContract)
end
end
end
Expand Down

0 comments on commit d5302e8

Please sign in to comment.