pinch_hitter 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rvmrc +52 -0
- data/.travis.yml +5 -0
- data/Changelog +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +33 -0
- data/Rakefile +19 -0
- data/config.ru +11 -0
- data/cucumber.yml +1 -0
- data/features/messages/car_rental.xml +77 -0
- data/features/messages/glossary.json +21 -0
- data/features/step_definitions/test_replay_steps.rb +35 -0
- data/features/support/env.rb +28 -0
- data/features/support/mock_web_service.rb +10 -0
- data/features/test_replay.feature +23 -0
- data/lib/pinch_hitter.rb +29 -0
- data/lib/pinch_hitter/core_ext/string.rb +5 -0
- data/lib/pinch_hitter/message/content_type.rb +15 -0
- data/lib/pinch_hitter/message/json.rb +38 -0
- data/lib/pinch_hitter/message/message_store.rb +34 -0
- data/lib/pinch_hitter/message/xml.rb +37 -0
- data/lib/pinch_hitter/service/replay_ws.rb +61 -0
- data/lib/pinch_hitter/service/response_queues.rb +29 -0
- data/lib/pinch_hitter/service/runner.rb +33 -0
- data/lib/pinch_hitter/version.rb +3 -0
- data/pinch_hitter.gemspec +29 -0
- data/test/test_json_message.rb +41 -0
- data/test/test_message.rb +67 -0
- data/test/test_pinch_hitter.rb +55 -0
- data/test/test_service.rb +113 -0
- data/test/test_xml_message.rb +52 -0
- metadata +222 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
|
7
|
+
# Only full ruby name is supported here, for short names use:
|
8
|
+
# echo "rvm use 1.9.3" > .rvmrc
|
9
|
+
environment_id="ruby-1.9.3-p327@pinch_hitter"
|
10
|
+
|
11
|
+
|
12
|
+
# First we attempt to load the desired environment directly from the environment
|
13
|
+
# file. This is very fast and efficient compared to running through the entire
|
14
|
+
# CLI and selector. If you want feedback on which environment was used then
|
15
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
16
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
17
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
18
|
+
then
|
19
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
20
|
+
|
21
|
+
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
22
|
+
then
|
23
|
+
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
24
|
+
fi
|
25
|
+
else
|
26
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
27
|
+
if ! rvm --create "$environment_id"
|
28
|
+
then
|
29
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
30
|
+
return 1
|
31
|
+
fi
|
32
|
+
fi
|
33
|
+
|
34
|
+
|
35
|
+
# If you use bundler, this might be useful to you:
|
36
|
+
if [[ -s Gemfile ]] && ! command -v bundle >/dev/null
|
37
|
+
then
|
38
|
+
printf "The rubygem 'bundler' is not installed. Installing it now.\n"
|
39
|
+
gem install bundler
|
40
|
+
fi
|
41
|
+
if [[ -s Gemfile ]] && command -v bundle
|
42
|
+
then
|
43
|
+
bundle install
|
44
|
+
fi
|
45
|
+
|
46
|
+
if [[ $- == *i* ]] # check for interactive shells
|
47
|
+
then
|
48
|
+
echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
|
49
|
+
else
|
50
|
+
echo "Using: $GEM_HOME" # don't use colors in interactive shells
|
51
|
+
fi
|
52
|
+
|
data/.travis.yml
ADDED
data/Changelog
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Steve Jackson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Pinch Hitter
|
2
|
+
Simple replay mock for web service testing
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
gem 'pinch_hitter'
|
9
|
+
|
10
|
+
And then execute:
|
11
|
+
|
12
|
+
$ bundle
|
13
|
+
|
14
|
+
Or install it yourself as:
|
15
|
+
|
16
|
+
$ gem install pinch_hitter
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Any xml posted to the /store endpoint will be returned (FIFO) when a post to the /respond endpoint is made.
|
21
|
+
|
22
|
+
Start the service using rackup
|
23
|
+
rackup
|
24
|
+
|
25
|
+
See Rakefile for test options
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rake/task'
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
|
7
|
+
Rake::TestTask.new(:unit) do |t|
|
8
|
+
t.libs << 'test'
|
9
|
+
t.pattern = 'test/**/test_*\.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
13
|
+
t.profile = 'default'
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Run all unit tests and features'
|
17
|
+
task :test => [:unit, :features]
|
18
|
+
|
19
|
+
task :default => :test
|
data/config.ru
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
libdir = File.dirname(__FILE__) + '/lib'
|
2
|
+
$LOAD_PATH.unshift libdir unless $LOAD_PATH.include? libdir
|
3
|
+
|
4
|
+
require 'pinch_hitter/service/replay_ws'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
class ::Logger; alias_method :write, :<<; end
|
8
|
+
logger = Logger.new('app.log')
|
9
|
+
use Rack::CommonLogger, logger
|
10
|
+
|
11
|
+
run PinchHitter::Service::ReplayWs
|
data/cucumber.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
default: --no-source --color --format pretty
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
|
2
|
+
<soapenv:Header></soapenv:Header>
|
3
|
+
<soapenv:Body>
|
4
|
+
<SubmitXmlResponse>
|
5
|
+
<SubmitXmlResult>
|
6
|
+
<CarStandardAvail_9 xmlns="">
|
7
|
+
<CarAvailDetail>
|
8
|
+
<Signature>0</Signature>
|
9
|
+
<DataQual>
|
10
|
+
<MktgTxtAry></MktgTxtAry>
|
11
|
+
<RateSepTextAry></RateSepTextAry>
|
12
|
+
<RefPt>GRAND FORKS MARK ANDREWS IN</RefPt>
|
13
|
+
<City>GFK</City>
|
14
|
+
<State>ND</State>
|
15
|
+
<Country>US</Country>
|
16
|
+
<DistUnit>M</DistUnit>
|
17
|
+
<RateTypeDesc>DAILY</RateTypeDesc>
|
18
|
+
<RateCatDesc> STND/PROM</RateCatDesc>
|
19
|
+
<Currency>USD</Currency>
|
20
|
+
<DecPos>2</DecPos>
|
21
|
+
<TruncDec>N</TruncDec>
|
22
|
+
<AltRateInd>5</AltRateInd>
|
23
|
+
<MoreCarsInd>N</MoreCarsInd>
|
24
|
+
<CarDetailAry>
|
25
|
+
<CarDetail>
|
26
|
+
<Vnd>ZI</Vnd>
|
27
|
+
<LocAffiliate>001</LocAffiliate>
|
28
|
+
<PrimeLocn>P</PrimeLocn>
|
29
|
+
<LinkInd>I</LinkInd>
|
30
|
+
<City>GFK</City>
|
31
|
+
<LocnCat>T</LocnCat>
|
32
|
+
<LocnExpansion></LocnExpansion>
|
33
|
+
<LocnNum>1</LocnNum>
|
34
|
+
<LocnCarRental>T</LocnCarRental>
|
35
|
+
<Dist></Dist>
|
36
|
+
<Dir>T</Dir>
|
37
|
+
<GeoLat></GeoLat>
|
38
|
+
<GeoLon></GeoLon>
|
39
|
+
<CarType>MVAR</CarType>
|
40
|
+
<YieldMgmt></YieldMgmt>
|
41
|
+
<Amt>10299</Amt>
|
42
|
+
<BaseRateAmt>10299</BaseRateAmt>
|
43
|
+
<DropChargeIncInd></DropChargeIncInd>
|
44
|
+
<UpsellInd></UpsellInd>
|
45
|
+
<RatePlcmtInd>3</RatePlcmtInd>
|
46
|
+
<RateType>D</RateType>
|
47
|
+
<RateGuar>G</RateGuar>
|
48
|
+
<AdditionalCharges></AdditionalCharges>
|
49
|
+
<AvailStatus>N</AvailStatus>
|
50
|
+
<MileRate>22</MileRate>
|
51
|
+
<Mile> 100</Mile>
|
52
|
+
<DropOffRestrictions>Y</DropOffRestrictions>
|
53
|
+
<RateCat>S</RateCat>
|
54
|
+
<MileageRestrictInd></MileageRestrictInd>
|
55
|
+
<FltInd></FltInd>
|
56
|
+
<CCInd></CCInd>
|
57
|
+
<Rate>2E</Rate>
|
58
|
+
<InclRateQual>
|
59
|
+
<RateDesc>DAILY PROMO</RateDesc>
|
60
|
+
<InclRate1></InclRate1>
|
61
|
+
<InclRate2></InclRate2>
|
62
|
+
<InclRate3></InclRate3>
|
63
|
+
<InclRate4></InclRate4>
|
64
|
+
<PrePayInd></PrePayInd>
|
65
|
+
<CarTypeDesc>FORD FREESTAR 4DR/7PS</CarTypeDesc>
|
66
|
+
<DropChargeAmt></DropChargeAmt>
|
67
|
+
<ApproxTotAmt>12762</ApproxTotAmt>
|
68
|
+
</InclRateQual>
|
69
|
+
</CarDetail>
|
70
|
+
</CarDetailAry>
|
71
|
+
</DataQual>
|
72
|
+
</CarAvailDetail>
|
73
|
+
</CarStandardAvail_9>
|
74
|
+
</SubmitXmlResult>
|
75
|
+
</SubmitXmlResponse>
|
76
|
+
</soapenv:Body>
|
77
|
+
</soapenv:Envelope>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{ "glossary": {
|
2
|
+
"title": "example glossary",
|
3
|
+
"GlossDiv": {
|
4
|
+
"title": "S",
|
5
|
+
"GlossList": {
|
6
|
+
"GlossEntry": {
|
7
|
+
"ID": "SGML",
|
8
|
+
"SortAs": "SGML",
|
9
|
+
"GlossTerm": "Standard Generalized Markup Language",
|
10
|
+
"Acronym": "SGML",
|
11
|
+
"Abbrev": "ISO 8879:1986",
|
12
|
+
"GlossDef": {
|
13
|
+
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
14
|
+
"GlossSeeAlso": ["GML", "XML"]
|
15
|
+
},
|
16
|
+
"GlossSee": "markup"
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Given /^I setup my replay service$/ do
|
2
|
+
mock.reset
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^I want a car rental$/ do
|
6
|
+
mock.prime '/car_rental', :car_rental
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I make a reservation$/ do
|
10
|
+
@response = app.post '/car_rental', ''
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^I see a car reservation$/ do
|
14
|
+
@response.body.to_s.should == messages.load(:car_rental).squish
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^I want a car rental with a "(.*?)" of "(.*?)"$/ do |tag, text|
|
18
|
+
mock.prime '/car_rental', :car_rental, tag => text
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /^I see a car reservation with a "(.*?)" of "(.*?)"$/ do |tag, text|
|
22
|
+
@response.body.to_s.should == messages.load(:car_rental, { tag => text }).squish
|
23
|
+
end
|
24
|
+
|
25
|
+
Given /^I want to lookup a definition$/ do
|
26
|
+
mock.prime '/glossary', :glossary
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^I query the glossary$/ do
|
30
|
+
@response = app.get "/glossary?term=SGML"
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^I see a definition$/ do
|
34
|
+
@response.body.to_s.should == messages.load(:glossary).squish
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rspec-expectations'
|
2
|
+
require 'pinch_hitter'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
def app_host
|
6
|
+
'127.0.0.1'
|
7
|
+
end
|
8
|
+
|
9
|
+
def app_port
|
10
|
+
9292
|
11
|
+
end
|
12
|
+
|
13
|
+
def app
|
14
|
+
@app ||= Net::HTTP.new app_host, app_port
|
15
|
+
end
|
16
|
+
|
17
|
+
def mock
|
18
|
+
@@mock ||= MockWebService.new app_host, app_port
|
19
|
+
end
|
20
|
+
|
21
|
+
def messages
|
22
|
+
mock.message_store
|
23
|
+
end
|
24
|
+
|
25
|
+
at_exit do
|
26
|
+
mock.stop_service
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Feature: Test WS replay
|
2
|
+
I want to test the ability to return a web service call on demand
|
3
|
+
As a tester trying to test the application
|
4
|
+
So that I can control my test data
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I setup my replay service
|
8
|
+
|
9
|
+
Scenario: Simple replay
|
10
|
+
Given I want a car rental
|
11
|
+
When I make a reservation
|
12
|
+
Then I see a car reservation
|
13
|
+
|
14
|
+
Scenario: Replay with subsititution
|
15
|
+
Given I want a car rental with a "City" of "ATL"
|
16
|
+
When I make a reservation
|
17
|
+
Then I see a car reservation with a "City" of "ATL"
|
18
|
+
|
19
|
+
Scenario: Replay with json
|
20
|
+
Given I want to lookup a definition
|
21
|
+
When I query the glossary
|
22
|
+
Then I see a definition
|
23
|
+
|
data/lib/pinch_hitter.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "pinch_hitter/version"
|
2
|
+
require "pinch_hitter/message/message_store"
|
3
|
+
require "pinch_hitter/service/runner"
|
4
|
+
|
5
|
+
module PinchHitter
|
6
|
+
include PinchHitter::Service::Runner
|
7
|
+
attr_accessor :message_store
|
8
|
+
|
9
|
+
def messages_directory=(dir)
|
10
|
+
self.message_store = PinchHitter::Message::MessageStore.new dir
|
11
|
+
end
|
12
|
+
|
13
|
+
def connect(host, port)
|
14
|
+
self.session = Net::HTTP.new host, port
|
15
|
+
end
|
16
|
+
|
17
|
+
def session=(session)
|
18
|
+
@session = session
|
19
|
+
end
|
20
|
+
|
21
|
+
def reset
|
22
|
+
@session.post '/reset', ''
|
23
|
+
end
|
24
|
+
|
25
|
+
def prime(endpoint, message, overrides={})
|
26
|
+
@session.post "/store?endpoint=#{endpoint}", message_store.load(message, overrides)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module PinchHitter
|
2
|
+
module Message
|
3
|
+
module Json
|
4
|
+
def json_message(file, overrides={})
|
5
|
+
json_file = load_json_file file
|
6
|
+
replace_json json_file, overrides
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid_json?(json)
|
10
|
+
begin
|
11
|
+
JSON.parse json
|
12
|
+
return true
|
13
|
+
rescue
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def load_json_file(filename)
|
20
|
+
IO.read filename
|
21
|
+
end
|
22
|
+
|
23
|
+
def replace_json(content, overrides={})
|
24
|
+
return content if overrides.empty?
|
25
|
+
modified = child = parent = JSON.parse(content).clone
|
26
|
+
overrides.each do |key, value|
|
27
|
+
|
28
|
+
key.each do |part|
|
29
|
+
parent = child
|
30
|
+
child = parent.send "fetch", part
|
31
|
+
end
|
32
|
+
parent[key.last] = value
|
33
|
+
end
|
34
|
+
modified.to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pinch_hitter/message/xml'
|
2
|
+
require 'pinch_hitter/message/json'
|
3
|
+
require 'pinch_hitter/message/content_type'
|
4
|
+
require 'pinch_hitter/core_ext/string'
|
5
|
+
|
6
|
+
module PinchHitter
|
7
|
+
module Message
|
8
|
+
class MessageStore
|
9
|
+
include Xml
|
10
|
+
include Json
|
11
|
+
include ContentType
|
12
|
+
|
13
|
+
attr_accessor :message_directory
|
14
|
+
|
15
|
+
def initialize(message_directory)
|
16
|
+
@message_directory = message_directory
|
17
|
+
end
|
18
|
+
|
19
|
+
def load(file, overrides={})
|
20
|
+
filename = find_filename file
|
21
|
+
if filename =~ /xml$/
|
22
|
+
xml_message filename, overrides
|
23
|
+
else
|
24
|
+
json_message filename, overrides
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_filename(file)
|
29
|
+
Dir["#{message_directory}/#{file}*"].first
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module PinchHitter
|
4
|
+
module Message
|
5
|
+
module Xml
|
6
|
+
def xml_message(file, overrides={})
|
7
|
+
xml = load_xml_file(file)
|
8
|
+
overrides.each do |key, text|
|
9
|
+
replace_xml(xml, key, text)
|
10
|
+
end
|
11
|
+
xml.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def load_xml_file(filename)
|
16
|
+
Nokogiri::XML File.open filename
|
17
|
+
end
|
18
|
+
|
19
|
+
def replace_xml(xml, key, text)
|
20
|
+
parts = key.split('@')
|
21
|
+
tag = find_node xml, parts.first
|
22
|
+
|
23
|
+
if parts.length == 1
|
24
|
+
#match text node
|
25
|
+
tag.content = text
|
26
|
+
else
|
27
|
+
#match attribute
|
28
|
+
tag[parts.last] = text
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_node(xml, tag)
|
33
|
+
xml.at_xpath("//#{tag}", xml.collect_namespaces)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
require 'pinch_hitter/service/response_queues'
|
7
|
+
require 'pinch_hitter/message/content_type'
|
8
|
+
|
9
|
+
module PinchHitter
|
10
|
+
module Service
|
11
|
+
class ReplayWs < Sinatra::Base
|
12
|
+
include PinchHitter::Message::ContentType
|
13
|
+
|
14
|
+
configure do
|
15
|
+
@@responses = ResponseQueues.new
|
16
|
+
#SOAP expects a mime_type of text/xml
|
17
|
+
mime_type :xml, "text/xml"
|
18
|
+
mime_type :json, "application/json"
|
19
|
+
end
|
20
|
+
|
21
|
+
post '/reset' do
|
22
|
+
@@responses.reset
|
23
|
+
200
|
24
|
+
end
|
25
|
+
|
26
|
+
post '/store/*' do
|
27
|
+
store "/#{params[:splat].first}", request.body.read
|
28
|
+
200
|
29
|
+
end
|
30
|
+
|
31
|
+
post '/store' do
|
32
|
+
store request["endpoint"], request.body.read
|
33
|
+
200
|
34
|
+
end
|
35
|
+
|
36
|
+
post '/respond' do
|
37
|
+
respond nil
|
38
|
+
end
|
39
|
+
|
40
|
+
get '/*' do
|
41
|
+
respond params[:splat].first
|
42
|
+
end
|
43
|
+
|
44
|
+
post '/*' do
|
45
|
+
respond params[:splat].first
|
46
|
+
end
|
47
|
+
|
48
|
+
def store(endpoint='/', message=nil)
|
49
|
+
@@responses.store endpoint, message
|
50
|
+
end
|
51
|
+
|
52
|
+
def respond(endpoint='/')
|
53
|
+
message = @@responses.retrieve endpoint
|
54
|
+
content_type determine_content_type message
|
55
|
+
puts "No message found for #{endpoint}" unless message
|
56
|
+
message
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PinchHitter
|
2
|
+
module Service
|
3
|
+
class ResponseQueues
|
4
|
+
|
5
|
+
def reset
|
6
|
+
@responses = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def responses
|
10
|
+
@responses ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def store(endpoint, body)
|
14
|
+
endpoint_responses(endpoint) << body.gsub(/\n\s*/, '')
|
15
|
+
end
|
16
|
+
|
17
|
+
def retrieve(endpoint='/')
|
18
|
+
endpoint_responses(endpoint).shift
|
19
|
+
end
|
20
|
+
|
21
|
+
def endpoint_responses(endpoint='/')
|
22
|
+
endpoint = "/#{endpoint}" unless endpoint =~ /^\//
|
23
|
+
queue = responses[endpoint] || []
|
24
|
+
responses[endpoint] = queue
|
25
|
+
queue
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'webrick'
|
3
|
+
require 'pinch_hitter/service/replay_ws'
|
4
|
+
|
5
|
+
module PinchHitter
|
6
|
+
module Service
|
7
|
+
module Runner
|
8
|
+
|
9
|
+
def start_service(host, port, timeout=10)
|
10
|
+
Thread.abort_on_exception = true
|
11
|
+
@app = PinchHitter::Service::ReplayWs.new
|
12
|
+
@replay_service = Thread.new do
|
13
|
+
Rack::Handler::WEBrick.run @app, :Host => host, :Port => port
|
14
|
+
end
|
15
|
+
wait_for_replay(timeout)
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop_service
|
19
|
+
@replay_service.kill
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def wait_for_replay(timeout)
|
24
|
+
end_time = ::Time.now + timeout
|
25
|
+
until ::Time.now > end_time
|
26
|
+
return if @replay_service.stop?
|
27
|
+
sleep 0.25
|
28
|
+
end
|
29
|
+
raise 'Timed out waiting for replay service to start'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pinch_hitter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "pinch_hitter"
|
8
|
+
gem.version = PinchHitter::VERSION
|
9
|
+
gem.authors = ["Steve Jackson"]
|
10
|
+
gem.email = ["steve.jackson@leandogsoftware.com"]
|
11
|
+
gem.description = %q{A simple web service that returns primed responses in FIFO order}
|
12
|
+
gem.summary = %q{Test utility for mocking out external web responses}
|
13
|
+
gem.homepage = "https://github.com/stevenjackson/pinch_hitter"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'sinatra', '>= 1.3.3'
|
21
|
+
gem.add_dependency 'nokogiri', '>= 1.5.6'
|
22
|
+
gem.add_dependency 'json', '>= 1.7.6'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'minitest', '>= 4.3.3'
|
25
|
+
gem.add_development_dependency 'rack-test', '>= 0.6.2'
|
26
|
+
gem.add_development_dependency 'rake', '>= 10.0.3'
|
27
|
+
gem.add_development_dependency 'rspec', '>= 2.12.0'
|
28
|
+
gem.add_development_dependency 'cucumber', '>= 1.2.1'
|
29
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
ENV['RACK_ENV'] = 'test'
|
3
|
+
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
class TestJsonMessage < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
File.open(filename, 'w') {|f| f.write(our_message) }
|
10
|
+
@test = Object.new
|
11
|
+
@test.extend(PinchHitter::Message::Json)
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
File.delete filename
|
16
|
+
end
|
17
|
+
|
18
|
+
def filename
|
19
|
+
"minitest_message.json"
|
20
|
+
end
|
21
|
+
|
22
|
+
def our_message
|
23
|
+
%Q{{"menu": {
|
24
|
+
"id": "file",
|
25
|
+
"value": "File",
|
26
|
+
"popup": {
|
27
|
+
"menuitem": "OpenDoc()"
|
28
|
+
}
|
29
|
+
}}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_message_no_overrides
|
34
|
+
assert_equal our_message, @test.json_message(filename)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_message_with_overrides
|
38
|
+
json = @test.json_message(filename, {["menu", "popup", "menuitem"] => 'WhatsUpDoc?' })
|
39
|
+
assert json.include? "WhatsUpDoc?"
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
ENV['RACK_ENV'] = 'test'
|
3
|
+
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'pinch_hitter/message/message_store'
|
6
|
+
class TestMessage < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
File.open("#{xml_filename}.xml", 'w') {|f| f.write(xml_message) }
|
10
|
+
|
11
|
+
File.open("#{json_file}", 'w') { |f| f.write(json_message) }
|
12
|
+
|
13
|
+
@messages = PinchHitter::Message::MessageStore.new File.dirname('.')
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
File.delete "#{xml_filename}.xml"
|
18
|
+
File.delete "#{json_file}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def xml_filename
|
22
|
+
"minitest_xml"
|
23
|
+
end
|
24
|
+
|
25
|
+
def json_file
|
26
|
+
"minitest_json"
|
27
|
+
end
|
28
|
+
|
29
|
+
def xml_message
|
30
|
+
%Q{<?xml version="1.0" encoding="UTF-8"?>
|
31
|
+
<Body/>
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def json_message
|
36
|
+
%Q{{
|
37
|
+
"one": "two",
|
38
|
+
"A": "B" }
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_setting_dir
|
43
|
+
@messages.message_directory = "/foo"
|
44
|
+
assert_equal "/foo", @messages.message_directory
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_loads_xml
|
48
|
+
assert_equal xml_message, @messages.load(xml_filename.to_sym)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_loads_json
|
52
|
+
assert_equal json_message, @messages.load(json_file.to_sym)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_message_no_whitespace
|
56
|
+
squish = %Q{<?xml version="1.0" encoding="UTF-8"?><Body/>}
|
57
|
+
assert_equal squish, @messages.load(xml_filename.to_sym).squish
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_content_type_defaults_to_xml
|
61
|
+
assert_equal "text/xml", @messages.determine_content_type("")
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_content_type_determines_json
|
65
|
+
assert_equal "application/json", @messages.determine_content_type(json_message)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'pinch_hitter/service/replay_ws'
|
4
|
+
require 'pinch_hitter'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'rack/test'
|
7
|
+
|
8
|
+
class TestPinchHitter < MiniTest::Unit::TestCase
|
9
|
+
include Rack::Test::Methods
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@test = Object.new
|
13
|
+
@test.extend(PinchHitter)
|
14
|
+
@test.session=session
|
15
|
+
@test.messages_directory = File.dirname('.')
|
16
|
+
File.open(message_file, 'w') {|f| f.write(message_content) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
File.delete message_file
|
21
|
+
end
|
22
|
+
|
23
|
+
def message_file
|
24
|
+
"fizzbuzz"
|
25
|
+
end
|
26
|
+
|
27
|
+
def message_content
|
28
|
+
"{fizzbuzz}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def app
|
32
|
+
PinchHitter::Service::ReplayWs
|
33
|
+
end
|
34
|
+
|
35
|
+
def session
|
36
|
+
@session ||= Rack::Test::Session.new(Rack::MockSession.new(app))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_message_store_init
|
40
|
+
@test.messages_directory = "/bar"
|
41
|
+
assert_equal "/bar", @test.message_store.message_directory
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_service_reset
|
45
|
+
@test.reset
|
46
|
+
assert_equal '/reset', session.last_request.path_info
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_prime
|
50
|
+
@test.prime '/foo', message_file.to_sym
|
51
|
+
session.get '/foo'
|
52
|
+
assert_equal message_content, session.last_response.body
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'pinch_hitter/service/replay_ws'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'rack/test'
|
6
|
+
require 'nokogiri'
|
7
|
+
|
8
|
+
class TestService < MiniTest::Unit::TestCase
|
9
|
+
include Rack::Test::Methods
|
10
|
+
|
11
|
+
def app
|
12
|
+
PinchHitter::Service::ReplayWs
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_retrieve
|
16
|
+
post "/store", xml_message
|
17
|
+
post "/respond", ''
|
18
|
+
|
19
|
+
assert_received xml_message
|
20
|
+
assert_equal 200, last_response.status
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def test_result_should_be_xml
|
25
|
+
post "/store", xml_message
|
26
|
+
post "/respond", ''
|
27
|
+
|
28
|
+
assert_equal 'text/xml;charset=utf-8', last_response.content_type
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_result_should_be_json
|
32
|
+
post "/store", yml_message
|
33
|
+
post "/respond", ''
|
34
|
+
|
35
|
+
assert_equal 'application/json;charset=utf-8', last_response.content_type
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_reset
|
39
|
+
post "/reset", ''
|
40
|
+
assert_equal 200, last_response.status
|
41
|
+
post "/respond", ''
|
42
|
+
assert_equal 200, last_response.status
|
43
|
+
assert_equal '', last_response.body
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_store_with_params
|
47
|
+
post '/store?endpoint=test2/subtest', yml_message
|
48
|
+
post '/test2/subtest', ''
|
49
|
+
|
50
|
+
assert_received yml_message
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_store_as_subendpoint
|
54
|
+
post '/store/test2/subtest', yml_message
|
55
|
+
post '/test2/subtest', ''
|
56
|
+
|
57
|
+
assert_received yml_message
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def test_multi_endpoints
|
62
|
+
post '/store/endpoint1', xml_message
|
63
|
+
post '/store/endpoint2', yml_message
|
64
|
+
|
65
|
+
post '/endpoint2', ''
|
66
|
+
assert_received yml_message
|
67
|
+
|
68
|
+
post '/endpoint1', ''
|
69
|
+
assert_received xml_message
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_multi_endpoint_queues
|
73
|
+
post '/store/endpoint1', xml_message
|
74
|
+
post '/store/endpoint1', xml_message
|
75
|
+
post '/store/endpoint2', yml_message
|
76
|
+
post '/store/endpoint2', yml_message
|
77
|
+
post '/store/endpoint2', yml_message
|
78
|
+
|
79
|
+
post '/endpoint2', ''
|
80
|
+
assert_received yml_message
|
81
|
+
post '/endpoint1', ''
|
82
|
+
assert_received xml_message
|
83
|
+
post '/endpoint1', ''
|
84
|
+
assert_received xml_message
|
85
|
+
post '/endpoint2', ''
|
86
|
+
assert_received yml_message
|
87
|
+
post '/endpoint2', ''
|
88
|
+
assert_received yml_message
|
89
|
+
#Out of queue
|
90
|
+
post '/endpoint1', ''
|
91
|
+
assert_equal '', last_response.body
|
92
|
+
end
|
93
|
+
|
94
|
+
def xml_message
|
95
|
+
message = %Q{<?xml version="1.0" encoding="UTF-8"?>
|
96
|
+
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:replay="http://www.leandog.com/replay">
|
97
|
+
<env:Body>
|
98
|
+
<replay:Response>BARK!</replay:Response>
|
99
|
+
</env:Body>
|
100
|
+
</env:Envelope>}
|
101
|
+
end
|
102
|
+
|
103
|
+
def yml_message
|
104
|
+
%Q~{"menu": {
|
105
|
+
"id": "file",
|
106
|
+
"value": "File"
|
107
|
+
}}~
|
108
|
+
end
|
109
|
+
|
110
|
+
def assert_received(message)
|
111
|
+
assert_equal message.gsub(/\n\s*/, ''), last_response.body.strip
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestXmlMessage < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
File.open(filename, 'w') {|f| f.write(our_message) }
|
9
|
+
@test = Object.new
|
10
|
+
@test.extend(PinchHitter::Message::Xml)
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
File.delete filename
|
15
|
+
end
|
16
|
+
|
17
|
+
def filename
|
18
|
+
"minitest_message.xml"
|
19
|
+
end
|
20
|
+
|
21
|
+
def our_message
|
22
|
+
%Q{<?xml version="1.0" encoding="UTF-8"?>
|
23
|
+
<wrapper>
|
24
|
+
<Body xmlns:ns="http://www.abc.org/OTA/2003/05">
|
25
|
+
<node>text</node>
|
26
|
+
<withattrib attrib="value"/>
|
27
|
+
<ns:testnode>text</ns:testnode>
|
28
|
+
</Body>
|
29
|
+
</wrapper>
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_message_no_overrides
|
34
|
+
assert_equal our_message, @test.xml_message(filename)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_message_tag_override
|
38
|
+
xml = @test.xml_message(filename, {"node" => "newtext"})
|
39
|
+
assert xml.include? "<node>newtext</node>"
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_message_tag_override_attrib
|
43
|
+
xml = @test.xml_message(filename,
|
44
|
+
{"withattrib@attrib" => "BetterValue"})
|
45
|
+
assert xml.include? "<withattrib attrib=\"BetterValue\""
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_message_tag_override_with_namespace
|
49
|
+
xml = @test.xml_message(filename, {"ns:testnode" => 'newValue'})
|
50
|
+
assert xml.include? "<ns:testnode>newValue</ns:testnode>"
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pinch_hitter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Steve Jackson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sinatra
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.3.3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.3.3
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: nokogiri
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.6
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.6
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: json
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.7.6
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.7.6
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 4.3.3
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 4.3.3
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rack-test
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.6.2
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.6.2
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rake
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 10.0.3
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 10.0.3
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.12.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 2.12.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: cucumber
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.2.1
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 1.2.1
|
142
|
+
description: A simple web service that returns primed responses in FIFO order
|
143
|
+
email:
|
144
|
+
- steve.jackson@leandogsoftware.com
|
145
|
+
executables: []
|
146
|
+
extensions: []
|
147
|
+
extra_rdoc_files: []
|
148
|
+
files:
|
149
|
+
- .gitignore
|
150
|
+
- .rvmrc
|
151
|
+
- .travis.yml
|
152
|
+
- Changelog
|
153
|
+
- Gemfile
|
154
|
+
- LICENSE
|
155
|
+
- README.md
|
156
|
+
- Rakefile
|
157
|
+
- config.ru
|
158
|
+
- cucumber.yml
|
159
|
+
- features/messages/car_rental.xml
|
160
|
+
- features/messages/glossary.json
|
161
|
+
- features/step_definitions/test_replay_steps.rb
|
162
|
+
- features/support/env.rb
|
163
|
+
- features/support/mock_web_service.rb
|
164
|
+
- features/test_replay.feature
|
165
|
+
- lib/pinch_hitter.rb
|
166
|
+
- lib/pinch_hitter/core_ext/string.rb
|
167
|
+
- lib/pinch_hitter/message/content_type.rb
|
168
|
+
- lib/pinch_hitter/message/json.rb
|
169
|
+
- lib/pinch_hitter/message/message_store.rb
|
170
|
+
- lib/pinch_hitter/message/xml.rb
|
171
|
+
- lib/pinch_hitter/service/replay_ws.rb
|
172
|
+
- lib/pinch_hitter/service/response_queues.rb
|
173
|
+
- lib/pinch_hitter/service/runner.rb
|
174
|
+
- lib/pinch_hitter/version.rb
|
175
|
+
- pinch_hitter.gemspec
|
176
|
+
- test/test_json_message.rb
|
177
|
+
- test/test_message.rb
|
178
|
+
- test/test_pinch_hitter.rb
|
179
|
+
- test/test_service.rb
|
180
|
+
- test/test_xml_message.rb
|
181
|
+
homepage: https://github.com/stevenjackson/pinch_hitter
|
182
|
+
licenses: []
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
require_paths:
|
186
|
+
- lib
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
188
|
+
none: false
|
189
|
+
requirements:
|
190
|
+
- - ! '>='
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
segments:
|
194
|
+
- 0
|
195
|
+
hash: -4118053142123846714
|
196
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
|
+
none: false
|
198
|
+
requirements:
|
199
|
+
- - ! '>='
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
segments:
|
203
|
+
- 0
|
204
|
+
hash: -4118053142123846714
|
205
|
+
requirements: []
|
206
|
+
rubyforge_project:
|
207
|
+
rubygems_version: 1.8.24
|
208
|
+
signing_key:
|
209
|
+
specification_version: 3
|
210
|
+
summary: Test utility for mocking out external web responses
|
211
|
+
test_files:
|
212
|
+
- features/messages/car_rental.xml
|
213
|
+
- features/messages/glossary.json
|
214
|
+
- features/step_definitions/test_replay_steps.rb
|
215
|
+
- features/support/env.rb
|
216
|
+
- features/support/mock_web_service.rb
|
217
|
+
- features/test_replay.feature
|
218
|
+
- test/test_json_message.rb
|
219
|
+
- test/test_message.rb
|
220
|
+
- test/test_pinch_hitter.rb
|
221
|
+
- test/test_service.rb
|
222
|
+
- test/test_xml_message.rb
|