fakettp 0.2.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.html ADDED
@@ -0,0 +1,113 @@
1
+ <h1>FakeTTP</h1>
2
+ <h2>Purpose</h2>
3
+ <p>When you are writing acceptance/integration tests for an application which makes <span class="caps">HTTP</span> requests to a remote application, sometimes you need to be able to test the interactions in different scenarios without talking to a real instance of the remote application.</p>
4
+ <p>FakeTTP is a standalone web application that allows you to mock requests (ie set and verify expectations on the requests your application makes, and return suitable responses to those requests).</p>
5
+ <h2>Installation</h2>
6
+ <h3>Install the gem</h3>
7
+ <p>Add GitHub as a gem source (you only need to do this once):</p>
8
+ <p><code>gem sources -a http://gems.github.com</code></p>
9
+ <p>Then install FakeTTP:</p>
10
+ <p><code>sudo gem install kerryb-fakettp</code></p>
11
+ <p>Alternatively, you can specify the source when you install the gem:</p>
12
+ <p><code>sudo gem install kerryb-fakettp --source http://gems.github.com</code></p>
13
+ <h3>Create a FakeTTP directory</h3>
14
+ <p>You can install FakeTTP anywhere that your web server user can see it:</p>
15
+ <p><code>fakettp install &lt;directory&gt;</code></p>
16
+ <h3>Point your web server at the directory</h3>
17
+ <p>FakeTTP should work with any Rack-compatible server: just point the server to the correct directory. For example, using <a href="http://www.modrails.com/">Passenger</a> (mod_rails) with Apache, create a virtual host along these lines:</p>
18
+ <pre><code>
19
+ &lt;VirtualHost *:80&gt;
20
+ ServerName fakettp.local
21
+ DocumentRoot "/path/to/fakettp/public"
22
+ &lt;directory "/path/to/fakettp/public"&gt;
23
+ Order deny,allow
24
+ Deny from all
25
+ Allow from 127.0.0.1
26
+ &lt;/directory&gt;
27
+ &lt;/VirtualHost&gt;
28
+ </code></pre>
29
+ <p>Then make sure <code>fakettp.local</code> resolves to 127.0.0.1 (assuming you&#8217;re running the simulator on the same machine as the application under test), eg by adding the following line to <code>/etc/hosts</code>:</p>
30
+ <p><code>127.0.0.1 fakettp.local</code></p>
31
+ <h3><span class="caps">IMPORTANT</span>: security note</h3>
32
+ <p>Because expectations are set by posting Ruby code to be executed on the server, you probably don&#8217;t want any old Tom, Dick or Harry to be able to connect. The security settings in the virtual host config example above restrict access to clients running on the local machine.</p>
33
+ <h2>Usage</h2>
34
+ <h3>Resetting</h3>
35
+ <p>To reset FakeTTP (ie remove all expectations and errors), make an <span class="caps">HTTP</span> <span class="caps">POST</span> request to <code>http://fakettp.local/reset</code>.</p>
36
+ <h4>Calling from curl</h4>
37
+ <p><code>curl fakettp.local/reset -X POST</code></p>
38
+ <h3>Setting expectations</h3>
39
+ <p>To create a new expectation, make an <span class="caps">HTTP</span> <span class="caps">POST</span> request to <code>http://fakettp.local/expect</code>, with a <em>Content-Type</em> header of &#8216;text/plain&#8217; and the request data containing a Ruby block to execute.</p>
40
+ <p>The supplied code should be in the following format, and will generally consist of a number of assertions on the request, followed by creation of the response to return to the application under test.</p>
41
+ <pre><code>
42
+ expect "GET of /foo" do
43
+ request.host.should == 'fakettp.local'
44
+ request.path_info.should == '/foo'
45
+
46
+ content_type 'text/plain'
47
+ "All is well\n"
48
+ end
49
+ </code></pre>
50
+ <p>The label on the first line is used in error reporting.</p>
51
+ <p>The expectation code has access to the underlying Sinatra request and response objects etc, as well as <a href="http://rspec.info">RSpec</a> matchers.</p>
52
+ <h4>Calling from curl</h4>
53
+ <p>Assuming the expectation is in <code>expectation_file</code>:</p>
54
+ <p><code>curl -X POST fakettp.local/expect -X POST -H 'Content-Type:text/plain' --binary-data @expectation_file</code></p>
55
+ <h3>Verifying</h3>
56
+ <p>To verify that all expectations have been met, make an <span class="caps">HTTP</span> <span class="caps">GET</span> request to <code>http://fakettp.local/verify</code>.</p>
57
+ <p>If all is well, the response will be a <em>200 OK</em> with a body of &#8216;OK&#8217;. Otherwise the status will be <em>400 Bad Request</em>, with a list of failures in the body. The failure messages include the complete details of the unexpected request that was received, to assist debugging.</p>
58
+ <h4>Calling from curl</h4>
59
+ <p><code>curl fakettp.local/verify</code></p>
60
+ <h3>Multiple hosts</h3>
61
+ <p>To have FakeTTP respond to multiple hostnames, create the appropriate hosts entries. If you&#8217;re using name-based virtual hosts in Apache, add a <em>ServerAlias</em> entry to the virtual host config, under the <em>ServerName</em> line, eg:</p>
62
+ <p><code>ServerAlias foo.com bar.com</code></p>
63
+ <h2>Change log</h2>
64
+ <p>0.2.4.1 (5 May 2009)</p>
65
+ <ul>
66
+ <li>Temporarily depend on edge version of Sinatra, to gain Rack 1.0 compatibility.</li>
67
+ </ul>
68
+ <p>0.2.4 (25 Mar 2009)</p>
69
+ <ul>
70
+ <li>Fixed a bug which caused expectations to be run in the wrong order if there were more than nine of them.</li>
71
+ </ul>
72
+ <p>0.2.3 (19 Mar 2009)</p>
73
+ <ul>
74
+ <li>Fixed a bug where expectations were being overwritten on Linux due to Dir.entries not returning results in the expected order</li>
75
+ </ul>
76
+ <p>0.2.2 (18 Mar 2009)</p>
77
+ <ul>
78
+ <li>Only accept control requests (reset, expect, verify) on fakettp.local</li>
79
+ </ul>
80
+ <p>0.2.1 (17 Mar 2009)</p>
81
+ <ul>
82
+ <li>Fixed issue where rspec matchers weren&#8217;t available to expectations</li>
83
+ </ul>
84
+ <p>0.2 (14 Mar 2009)</p>
85
+ <ul>
86
+ <li>Complete rewrite, with tests and classes and stuff this time.</li>
87
+ </ul>
88
+ <p>If you get an &#8216;unexpected return&#8217; error, remove the return statement from your expectation, and just put the return value on the last line of the <em>expect</em> block.</p>
89
+ <p>0.1.2 (13 Feb 2009)</p>
90
+ <ul>
91
+ <li>Make sure <span class="caps">README</span>.html appears in generated gem</li>
92
+ </ul>
93
+ <p>0.1.1 (13 Feb 2009)</p>
94
+ <ul>
95
+ <li>Fix permissions on installed tmp directory.</li>
96
+ </ul>
97
+ <p>0.1.0 (13 Feb 2009)</p>
98
+ <ul>
99
+ <li>First release as a gem.</li>
100
+ </ul>
101
+ <h2>To Do</h2>
102
+ <ul>
103
+ <li>Add examples</li>
104
+ <li>Make control requests RESTful?</li>
105
+ <li>Make main hostname configurable?</li>
106
+ <li>Show label in verification error for expected requests that weren&#8217;t received</li>
107
+ <li>Add facility to stub as well as mock requests</li>
108
+ <li>Allow more flexibility in request ordering</li>
109
+ <li>Allow user-specific helper files in installation dir</li>
110
+ <li>Check install/run behaviour when development dependencies are not installed</li>
111
+ <li>Provide Ruby <span class="caps">API</span> to set expectations etc</li>
112
+ <li>Return the expected content type even if expectation fails</li>
113
+ </ul>
data/bin/fakettp ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fakettp/commands/fakettp_command'
4
+
5
+ exit Fakettp::Commands::FakettpCommand.new(ARGV).run
@@ -0,0 +1,53 @@
1
+ module Fakettp
2
+ module Commands
3
+ class FakettpCommand
4
+ def initialize args
5
+ @args = args
6
+ end
7
+
8
+ def run
9
+ command = get_command
10
+ return usage unless command
11
+ case command
12
+ when 'install' then
13
+ return install
14
+ else
15
+ return usage
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def get_command
22
+ @args[0]
23
+ end
24
+
25
+ def install
26
+ dir = get_dir
27
+ return usage unless dir
28
+ if File.exist? dir
29
+ $stderr.puts "File or directory #{dir} already exists."
30
+ return 1
31
+ end
32
+ FileUtils.mkdir_p dir + '/tmp/expectations', :mode => 0777
33
+ FileUtils.mkdir_p dir + '/public'
34
+ FileUtils.cp File.dirname(__FILE__) + '/../config.ru', dir
35
+ FileUtils.cp File.dirname(__FILE__) + '/../../../README.html', dir
36
+ return 0
37
+ end
38
+
39
+ def get_dir
40
+ @args[1]
41
+ end
42
+
43
+ def usage
44
+ $stderr.puts <<-EOF
45
+ Usage:
46
+
47
+ [TODO]
48
+ EOF
49
+ return 1
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+
3
+ FAKETTP_BASE = File.expand_path(File.dirname(__FILE__))
4
+ require 'fakettp'
5
+
6
+ run Sinatra::Application
@@ -0,0 +1,42 @@
1
+ require 'sinatra'
2
+ require 'spec'
3
+ Sinatra::Default.set :run, false
4
+ Sinatra::Default.set :environment, ENV['RACK_ENV']
5
+
6
+ require 'fakettp/expectation_helper'
7
+ require 'fakettp/simulator'
8
+ require 'fakettp/expectation'
9
+
10
+ include Fakettp::ExpectationHelper
11
+
12
+ post '/expect', :host => 'fakettp.local' do
13
+ Fakettp::Simulator << request.body.read
14
+ content_type 'text/plain'
15
+ "Expect OK\n"
16
+ end
17
+
18
+ post '/reset', :host => 'fakettp.local' do
19
+ Fakettp::Simulator.reset
20
+ content_type 'text/plain'
21
+ "Reset OK\n"
22
+ end
23
+
24
+ get '/verify', :host => 'fakettp.local' do
25
+ content_type 'text/plain'
26
+ if Fakettp::Simulator.verify
27
+ "Verify OK\n"
28
+ else
29
+ throw :halt, [500, Fakettp::Simulator.list_errors]
30
+ end
31
+ end
32
+
33
+ [:get, :post, :put, :delete, :head].each do |method|
34
+ send method, '/**' do
35
+ begin
36
+ Fakettp::Simulator.handle_request binding
37
+ rescue Fakettp::Expectation::Error => e
38
+ content_type 'text/plain'
39
+ throw :halt, [500, "Simulator received mismatched request\n"]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ module Fakettp
2
+ class Error
3
+ ERROR_FILE = File.join FAKETTP_BASE, 'tmp', 'errors'
4
+
5
+ def self.clear_all
6
+ FileUtils.rm_rf ERROR_FILE
7
+ end
8
+
9
+ def self.<< message
10
+ File.open ERROR_FILE, 'a' do |f|
11
+ f.puts message
12
+ end
13
+ end
14
+
15
+ def self.empty?
16
+ !File.exists? ERROR_FILE
17
+ end
18
+
19
+ def self.list
20
+ empty? ? '' : File.read(ERROR_FILE)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ module Fakettp
2
+ class Expectation
3
+ class Error < Exception; end
4
+
5
+ EXPECTATION_DIR = File.join FAKETTP_BASE, 'tmp', 'expectations'
6
+
7
+ def initialize contents
8
+ @contents = contents
9
+ end
10
+
11
+ def execute binding
12
+ eval @contents, binding
13
+ # TODO: Include context of expectation file
14
+ end
15
+
16
+ def self.clear_all
17
+ FileUtils.rm_rf Dir.glob(File.join(EXPECTATION_DIR, '*'))
18
+ end
19
+
20
+ def self.empty?
21
+ files.empty?
22
+ end
23
+
24
+ def self.<< expectation
25
+ File.open next_file_to_create, 'w' do |f|
26
+ f.write expectation
27
+ end
28
+ end
29
+
30
+ def self.next
31
+ file = next_file_to_read
32
+ contents = File.read file
33
+ FileUtils.rm file
34
+ Expectation.new contents
35
+ end
36
+
37
+ private
38
+
39
+ def self.next_file_to_create
40
+ name = (files.last.to_i + 1).to_s
41
+ File.join EXPECTATION_DIR, name
42
+ end
43
+
44
+ def self.next_file_to_read
45
+ name = files.first
46
+ raise Error.new('Received unexpected request') unless name
47
+ File.join EXPECTATION_DIR, name
48
+ end
49
+
50
+ def self.files
51
+ (Dir.entries(EXPECTATION_DIR) - ['.', '..']).sort_by {|a| a.to_i}
52
+ end
53
+
54
+ private_class_method :next_file_to_create, :next_file_to_read, :files
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ require 'fakettp/expectation'
2
+
3
+ module Fakettp
4
+ module ExpectationHelper
5
+ def self.included(cls)
6
+ cls.send :include, Spec::Matchers
7
+ end
8
+
9
+ def expect label
10
+ begin
11
+ yield
12
+ rescue Exception => e
13
+ raise Fakettp::Expectation::Error.new("Error in #{label}: #{e.message}")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ require 'fakettp/expectation'
2
+ require 'fakettp/error'
3
+
4
+ module Fakettp
5
+ class Simulator
6
+ def self.reset
7
+ Expectation.clear_all
8
+ Error.clear_all
9
+ end
10
+
11
+ def self.verify
12
+ Error << 'Expected request not received' unless Expectation.empty?
13
+ Error.empty?
14
+ end
15
+
16
+ def self.<< expectation
17
+ Expectation << expectation
18
+ end
19
+
20
+ def self.handle_request binding
21
+ begin
22
+ Expectation.next.execute binding
23
+ rescue Fakettp::Expectation::Error => e
24
+ Error << e.message
25
+ raise e
26
+ end
27
+ end
28
+
29
+ def self.list_errors
30
+ Error.list
31
+ end
32
+ end
33
+ end
data/lib/fakettp.rb ADDED
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'fakettp/controller'
3
+ require 'fakettp/commands/fakettp_command'
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fakettp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Kerry Buckley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-13 00:00:00 +01:00
13
+ default_executable: fakettp
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra-sinatra
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.1.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.12
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: spicycode-rcov
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.8.0
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: cucumber
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.16
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: RedCloth
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 4.1.1
64
+ version:
65
+ description:
66
+ email: kerryjbuckley@gmail.com
67
+ executables:
68
+ - fakettp
69
+ extensions: []
70
+
71
+ extra_rdoc_files: []
72
+
73
+ files:
74
+ - lib/fakettp/commands/fakettp_command.rb
75
+ - lib/fakettp/config.ru
76
+ - lib/fakettp/controller.rb
77
+ - lib/fakettp/error.rb
78
+ - lib/fakettp/expectation.rb
79
+ - lib/fakettp/expectation_helper.rb
80
+ - lib/fakettp/simulator.rb
81
+ - lib/fakettp.rb
82
+ - bin/fakettp
83
+ - README.html
84
+ has_rdoc: true
85
+ homepage: http://github.com/kerryb/fakettp/
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options: []
90
+
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ version:
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "0"
104
+ version:
105
+ requirements: []
106
+
107
+ rubyforge_project: fakettp
108
+ rubygems_version: 1.3.2
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: HTTP server mocking tool
112
+ test_files: []
113
+