pinch_hitter 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|