anmo 0.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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in anmo.gemspec
4
+ gemspec
@@ -0,0 +1,3 @@
1
+ guard 'shell' do
2
+ watch(/lib|test\/.*rb/) {|m| system "rake test" }
3
+ end
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :test do
4
+ Dir.glob("test/**/*_test.rb").each do |f|
5
+ require File.expand_path(File.join(File.dirname(__FILE__), f))
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "anmo/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "anmo"
7
+ s.version = Anmo::VERSION
8
+ s.authors = ["Andrew Vos"]
9
+ s.email = ["andrew.vos@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{}
12
+ s.description = %q{}
13
+
14
+ s.rubyforge_project = "anmo"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "rack"
22
+ s.add_runtime_dependency "thin"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "minitest"
25
+ s.add_development_dependency "rack-test"
26
+ s.add_development_dependency "cucumber"
27
+ s.add_development_dependency "rspec"
28
+ s.add_development_dependency "guard"
29
+ s.add_development_dependency "httparty"
30
+ s.add_development_dependency "guard-shell"
31
+ end
@@ -0,0 +1,115 @@
1
+ Feature: API
2
+ In order to test applications against stable APIs
3
+ As a developer
4
+ I want to be able to mock http endpoints
5
+
6
+ Scenario: Launch a server
7
+ When I execute the following code in a new thread
8
+ """
9
+ Anmo.launch_server
10
+ """
11
+ Then I see an anmo server on port 8787
12
+
13
+ Scenario: Launch a server with a port
14
+ When I execute the following code in a new thread
15
+ """
16
+ Anmo.launch_server 9393
17
+ """
18
+ Then I see an anmo server on port 9393
19
+
20
+ Scenario: Create a request
21
+ Given an anmo server
22
+ When I execute the code
23
+ """
24
+ Anmo.server = "http://localhost:8787"
25
+ Anmo.create_request({
26
+ :path => "/lollll",
27
+ :body => "can't think of anything",
28
+ :required_headers => {"meh" => "bleh", "blah" => "blah"}
29
+ })
30
+ """
31
+ And I request the uri "http://localhost:8787/lollll" with the headers
32
+ """
33
+ {
34
+ "meh": "bleh",
35
+ "blah": "blah"
36
+ }
37
+ """
38
+ Then I see the response body "can't think of anything"
39
+
40
+ Scenario: Save object
41
+ Given an anmo server
42
+ When I execute the code
43
+ """
44
+ Anmo.server = "http://localhost:8787"
45
+ Anmo.create_request({
46
+ :path => "/some/object",
47
+ :body => "some data"
48
+ })
49
+ """
50
+ And I request the uri "http://localhost:8787/some/object"
51
+ Then I see the response body "some data"
52
+
53
+ Scenario: Save object with http status code
54
+ Given an anmo server
55
+ When I execute the code
56
+ """
57
+ Anmo.server = "http://localhost:8787"
58
+ Anmo.create_request({
59
+ :path => "/some/object",
60
+ :status => 123
61
+ })
62
+ """
63
+ And I request the uri "http://localhost:8787/some/object"
64
+ Then I see the response code 123
65
+
66
+ Scenario: Request without required headers 404s
67
+ Given an anmo server
68
+ When I execute the code
69
+ """
70
+ Anmo.server = "http://localhost:8787"
71
+ Anmo.create_request({
72
+ :path => "/some/object",
73
+ :required_headers => {:meh => "bleh", :durp => "derp"}
74
+ })
75
+ """
76
+ And I request the uri "http://localhost:8787/some/object"
77
+ Then I see the response code 404
78
+
79
+ Scenario: Request with required headers
80
+ Given an anmo server
81
+ When I execute the code
82
+ """
83
+ Anmo.server = "http://localhost:8787"
84
+ Anmo.create_request({
85
+ :path => "/some/object",
86
+ :body => "helloow",
87
+ :required_headers => {:meh => "bleh", :durp => "derp"}
88
+ })
89
+ """
90
+ And I request the uri "http://localhost:8787/some/object" with the headers
91
+ """
92
+ {
93
+ "meh": "bleh",
94
+ "durp": "derp"
95
+ }
96
+ """
97
+ Then I see the response body "helloow"
98
+ And I see the response code 200
99
+
100
+ Scenario: Delete all saved objects
101
+ Given an anmo server
102
+ When I execute the code
103
+ """
104
+ Anmo.server = "http://localhost:8787"
105
+ Anmo.create_request({
106
+ :path => "/some/object",
107
+ :body => "some data"
108
+ })
109
+ """
110
+ And I execute the code
111
+ """
112
+ Anmo.delete_all
113
+ """
114
+ And I request the uri "http://localhost:8787/some/object"
115
+ Then I see the response code 404
@@ -0,0 +1,51 @@
1
+ When /^I execute the following code in a new thread$/ do |code|
2
+ Thread.new do
3
+ eval code
4
+ end
5
+ end
6
+
7
+ When /^I execute the code$/ do |code|
8
+ eval code
9
+ end
10
+
11
+ Then /^I see an anmo server on port (\d+)$/ do |port|
12
+ response = nil
13
+
14
+ timeout 5 do
15
+ while response.nil?
16
+ response = HTTParty.get("http://localhost:#{port}") rescue nil
17
+ end
18
+ end
19
+
20
+ response.body.should include "Not Found"
21
+ end
22
+
23
+ Given /^an anmo server$/ do
24
+ Thread.new do
25
+ Anmo.launch_server
26
+ end
27
+ timeout 5 do
28
+ response = nil
29
+ while response.nil?
30
+ response = HTTParty.get("http://localhost:8787") rescue nil
31
+ end
32
+ sleep 0.1
33
+ end
34
+ end
35
+
36
+ When /^I request the uri "([^"]*)"$/ do |uri|
37
+ @response = HTTParty.get(uri)
38
+ end
39
+
40
+ When /^I request the uri "([^"]*)" with the headers$/ do |uri, headers|
41
+ headers = JSON.parse(headers)
42
+ @response = HTTParty.get(uri, :headers => headers)
43
+ end
44
+
45
+ Then /^I see the response body "([^"]*)"$/ do |body|
46
+ @response.body.should == body
47
+ end
48
+
49
+ Then /^I see the response code (\d+)$/ do |code|
50
+ @response.code.should == code.to_i
51
+ end
@@ -0,0 +1,13 @@
1
+ require "rack"
2
+ require "rack/test"
3
+ require "httparty"
4
+
5
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "../../lib")))
6
+ require "anmo"
7
+ require "anmo/application"
8
+
9
+ World(Rack::Test::Methods)
10
+
11
+ def app
12
+ Anmo::Application.new
13
+ end
@@ -0,0 +1,21 @@
1
+ require "anmo/version"
2
+ require "anmo/application"
3
+ require "thin"
4
+
5
+ module Anmo
6
+ class << self
7
+ attr_accessor :server
8
+ end
9
+
10
+ def self.launch_server port = 8787
11
+ Thin::Server.start("0.0.0.0", port, Anmo::Application.new)
12
+ end
13
+
14
+ def self.create_request options
15
+ HTTParty.put("#{server}/__CREATE__", :body => options.to_json)
16
+ end
17
+
18
+ def self.delete_all
19
+ HTTParty.put("#{server}/__DELETE_ALL__")
20
+ end
21
+ end
@@ -0,0 +1,65 @@
1
+ require "ostruct"
2
+
3
+ module Anmo
4
+ class Application
5
+ def call env
6
+ @stored_requests ||= []
7
+ request = Rack::Request.new(env)
8
+
9
+ if request.path_info == "/__CREATE__"
10
+ process_create_request request
11
+ elsif request.path_info == "/__DELETE_ALL__"
12
+ process_delete_all_request request
13
+ else
14
+ process_normal_request request
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def process_create_request request
21
+ request_info = JSON.parse(read_request_body(request))
22
+ @stored_requests.unshift(request_info)
23
+ [201, {}, ""]
24
+ end
25
+
26
+ def process_delete_all_request request
27
+ @stored_requests = []
28
+ [200, {}, ""]
29
+ end
30
+
31
+ def process_normal_request request
32
+ if found_request = find_stored_request(request)
33
+ [Integer(found_request["status"]||200), {"Content-Type" => "text/html"}, [found_request["body"]]]
34
+ else
35
+ [404, {"Content-Type" => "text/html"}, "Not Found"]
36
+ end
37
+ end
38
+
39
+ def find_stored_request actual_request
40
+ found_request = @stored_requests.find {|r| r["path"] == actual_request.path_info}
41
+ if found_request
42
+ required_headers = found_request["required_headers"] || []
43
+ required_headers.each do |name, value|
44
+ if actual_request.env[convert_header_name_to_rack_style_name(name)] != value
45
+ found_request = nil
46
+ break
47
+ end
48
+ end
49
+ end
50
+ found_request
51
+ end
52
+
53
+ def convert_header_name_to_rack_style_name name
54
+ name = "HTTP_#{name}"
55
+ name.gsub!("-", "_")
56
+ name.upcase!
57
+ name
58
+ end
59
+
60
+ def read_request_body request
61
+ request.body.rewind
62
+ request.body.read
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module Anmo
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,86 @@
1
+ require "minitest/pride"
2
+ require "minitest/autorun"
3
+ require "minitest/unit"
4
+ require "rack/test"
5
+ require "json"
6
+ require File.expand_path(File.join(File.dirname(__FILE__), "../../lib/anmo/application"))
7
+
8
+ module Anmo
9
+ class ApplicationTest < MiniTest::Unit::TestCase
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ Application.new
14
+ end
15
+
16
+ def save_object path, body, status, required_headers
17
+ options = {
18
+ :path => path,
19
+ :body => body,
20
+ :status => status,
21
+ :required_headers => required_headers
22
+ }
23
+ put "__CREATE__", options.to_json
24
+ end
25
+
26
+ def test_404s_if_object_does_not_exist
27
+ get "/bla/bla/bla.json"
28
+ assert_equal "Not Found", last_response.body
29
+ assert last_response.not_found?
30
+ end
31
+
32
+ def test_stores_mock_data
33
+ save_object "/this/is/the/path.object", "please save this", nil, nil
34
+ assert_equal 201, last_response.status
35
+
36
+ get "/this/is/the/path.object"
37
+ assert_equal "please save this", last_response.body
38
+ assert last_response.ok?
39
+ end
40
+
41
+ def test_stores_status_code
42
+ save_object "/monkeys", nil, 123, nil
43
+ get "/monkeys"
44
+ assert_equal 123, last_response.status
45
+ end
46
+
47
+ def test_allows_deleting_all_objects
48
+ save_object "/this/is/the/path.object", "please save this", nil, nil
49
+
50
+ get "/this/is/the/path.object"
51
+ first_response = last_response
52
+
53
+ put "__DELETE_ALL__"
54
+ assert_equal 200, last_response.status
55
+
56
+ get "/this/is/the/path.object"
57
+ second_response = last_response
58
+
59
+ assert_equal "please save this", first_response.body
60
+ assert_equal "Not Found", second_response.body
61
+ assert_equal 404, second_response.status
62
+ end
63
+
64
+ def test_404s_if_request_does_not_have_required_headers
65
+ save_object "/oh/hai", nil, nil, {"ruby" => "hipsters", "meh" => "bleh"}
66
+ get "/oh/hai"
67
+ assert_equal 404, last_response.status
68
+ end
69
+
70
+ def test_returns_value_if_request_has_required_headers
71
+ save_object "/oh/hai", "the content", nil, {"lol-ruby" => "hipsters", "meh" => "bleh"}
72
+ header "lol-ruby", "hipsters"
73
+ header "meh", "bleh"
74
+ get "/oh/hai"
75
+ assert_equal 200, last_response.status
76
+ assert_equal "the content", last_response.body
77
+ end
78
+
79
+ def test_returns_the_last_added_object_first
80
+ save_object "/oh/hai", "the first content", nil, nil
81
+ save_object "/oh/hai", "the second content", nil, nil
82
+ get "/oh/hai"
83
+ assert_equal "the second content", last_response.body
84
+ end
85
+ end
86
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: anmo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrew Vos
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-26 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &70320251647360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70320251647360
25
+ - !ruby/object:Gem::Dependency
26
+ name: thin
27
+ requirement: &70320251646940 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70320251646940
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70320251646520 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70320251646520
47
+ - !ruby/object:Gem::Dependency
48
+ name: minitest
49
+ requirement: &70320251646100 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70320251646100
58
+ - !ruby/object:Gem::Dependency
59
+ name: rack-test
60
+ requirement: &70320251645680 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70320251645680
69
+ - !ruby/object:Gem::Dependency
70
+ name: cucumber
71
+ requirement: &70320251645260 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70320251645260
80
+ - !ruby/object:Gem::Dependency
81
+ name: rspec
82
+ requirement: &70320251644840 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70320251644840
91
+ - !ruby/object:Gem::Dependency
92
+ name: guard
93
+ requirement: &70320251644420 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70320251644420
102
+ - !ruby/object:Gem::Dependency
103
+ name: httparty
104
+ requirement: &70320251644000 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *70320251644000
113
+ - !ruby/object:Gem::Dependency
114
+ name: guard-shell
115
+ requirement: &70320251643580 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *70320251643580
124
+ description: ''
125
+ email:
126
+ - andrew.vos@gmail.com
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files: []
130
+ files:
131
+ - .gitignore
132
+ - Gemfile
133
+ - Guardfile
134
+ - Rakefile
135
+ - anmo.gemspec
136
+ - features/api.feature
137
+ - features/step_definitions/api_steps.rb
138
+ - features/support/env.rb
139
+ - lib/anmo.rb
140
+ - lib/anmo/application.rb
141
+ - lib/anmo/version.rb
142
+ - test/anmo/application_test.rb
143
+ homepage: ''
144
+ licenses: []
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ! '>='
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ requirements: []
162
+ rubyforge_project: anmo
163
+ rubygems_version: 1.8.10
164
+ signing_key:
165
+ specification_version: 3
166
+ summary: ''
167
+ test_files:
168
+ - features/api.feature
169
+ - features/step_definitions/api_steps.rb
170
+ - features/support/env.rb
171
+ - test/anmo/application_test.rb