batch_api 0.1.1 → 0.2.0
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/changelog.md +17 -0
- data/lib/batch_api.rb +6 -1
- data/lib/batch_api/batch_error.rb +41 -0
- data/lib/batch_api/configuration.rb +31 -21
- data/lib/batch_api/error_wrapper.rb +44 -0
- data/lib/batch_api/internal_middleware.rb +87 -0
- data/lib/batch_api/internal_middleware/decode_json_body.rb +24 -0
- data/lib/batch_api/internal_middleware/response_filter.rb +27 -0
- data/lib/batch_api/operation/rack.rb +4 -5
- data/lib/batch_api/processor.rb +22 -20
- data/lib/batch_api/processor/executor.rb +18 -0
- data/lib/batch_api/processor/sequential.rb +29 -0
- data/lib/batch_api/{middleware.rb → rack_middleware.rb} +2 -2
- data/lib/batch_api/response.rb +10 -8
- data/lib/batch_api/version.rb +1 -1
- data/readme.md +179 -106
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +15 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/javascripts/endpoints.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/endpoints.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/endpoints_controller.rb +36 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/endpoints_helper.rb +2 -0
- data/spec/dummy/app/views/endpoints/get.html.erb +2 -0
- data/spec/dummy/app/views/endpoints/post.html.erb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +63 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +64 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +1742 -0
- data/spec/dummy/log/test.log +48237 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/test/functional/endpoints_controller_test.rb +14 -0
- data/spec/dummy/test/unit/helpers/endpoints_helper_test.rb +4 -0
- data/spec/integration/rails_spec.rb +10 -0
- data/spec/integration/shared_examples.rb +256 -0
- data/spec/integration/sinatra_integration_spec.rb +14 -0
- data/spec/lib/batch_api_spec.rb +20 -0
- data/spec/lib/batch_error_spec.rb +23 -0
- data/spec/lib/configuration_spec.rb +30 -0
- data/spec/lib/error_wrapper_spec.rb +68 -0
- data/spec/lib/internal_middleware/decode_json_body_spec.rb +37 -0
- data/spec/lib/internal_middleware/response_filter_spec.rb +61 -0
- data/spec/lib/internal_middleware_spec.rb +91 -0
- data/spec/lib/operation/rack_spec.rb +243 -0
- data/spec/lib/operation/rails_spec.rb +100 -0
- data/spec/lib/processor/executor_spec.rb +22 -0
- data/spec/lib/processor/sequential_spec.rb +39 -0
- data/spec/lib/processor_spec.rb +134 -0
- data/spec/lib/rack_middleware_spec.rb +103 -0
- data/spec/lib/response_spec.rb +53 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/sinatra_app.rb +54 -0
- metadata +148 -12
- data/lib/batch_api/error.rb +0 -3
- data/lib/batch_api/errors/base.rb +0 -45
- data/lib/batch_api/errors/operation.rb +0 -7
- data/lib/batch_api/errors/request.rb +0 -26
- data/lib/batch_api/processor/strategies/sequential.rb +0 -18
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'batch_api/error_wrapper'
|
3
|
+
|
4
|
+
describe BatchApi::ErrorWrapper do
|
5
|
+
let(:exception) {
|
6
|
+
StandardError.new(Faker::Lorem.words(3)).tap do |e|
|
7
|
+
e.set_backtrace(Kernel.caller)
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
let(:error) { BatchApi::ErrorWrapper.new(exception) }
|
12
|
+
|
13
|
+
describe "#body" do
|
14
|
+
it "includes the message in the body" do
|
15
|
+
error.body[:error][:message].should == exception.message
|
16
|
+
end
|
17
|
+
|
18
|
+
it "includes the backtrace if it should be there" do
|
19
|
+
error.stub(:expose_backtrace?).and_return(true)
|
20
|
+
error.body[:error][:backtrace].should == exception.backtrace
|
21
|
+
end
|
22
|
+
|
23
|
+
it "includes the backtrace if it should be there" do
|
24
|
+
error.stub(:expose_backtrace?).and_return(false)
|
25
|
+
error.body[:backtrace].should be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#render" do
|
30
|
+
it "returns the appropriate status" do
|
31
|
+
status = stub
|
32
|
+
error.stub(:status_code).and_return(status)
|
33
|
+
error.render[0].should == status
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns appropriate content type" do
|
37
|
+
ctype = stub
|
38
|
+
BatchApi::RackMiddleware.stub(:content_type).and_return(ctype)
|
39
|
+
error.render[1].should == ctype
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns the JSONified body as the 2nd" do
|
43
|
+
error.render[2].should == [MultiJson.dump(error.body)]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#status_code" do
|
48
|
+
it "returns 500 by default" do
|
49
|
+
error.status_code.should == 500
|
50
|
+
end
|
51
|
+
|
52
|
+
it "returns another status code if the error supports that" do
|
53
|
+
err = StandardError.new
|
54
|
+
code = stub
|
55
|
+
err.stub(:status_code).and_return(code)
|
56
|
+
BatchApi::ErrorWrapper.new(err).status_code.should == code
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe ".expose_backtrace?" do
|
61
|
+
it "returns false if Rails.env.production?" do
|
62
|
+
Rails.env.stub(:production?).and_return(true)
|
63
|
+
BatchApi::ErrorWrapper.expose_backtrace?.should be_false
|
64
|
+
Rails.env.stub(:production?).and_return(false)
|
65
|
+
BatchApi::ErrorWrapper.expose_backtrace?.should be_true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchApi::InternalMiddleware::DecodeJsonBody do
|
4
|
+
let(:app) { stub("app", call: result) }
|
5
|
+
let(:decoder) { BatchApi::InternalMiddleware::DecodeJsonBody.new(app) }
|
6
|
+
let(:env) { stub("env") }
|
7
|
+
let(:json) { {"data" => "is_json", "more" => {"hi" => "there"} } }
|
8
|
+
let(:result) {
|
9
|
+
BatchApi::Response.new([
|
10
|
+
200,
|
11
|
+
{"Content-Type" => "application/json"},
|
12
|
+
[MultiJson.dump(json)]
|
13
|
+
])
|
14
|
+
}
|
15
|
+
|
16
|
+
describe "#call" do
|
17
|
+
context "for json results" do
|
18
|
+
it "decodes JSON results for application/json responses" do
|
19
|
+
result = decoder.call(env)
|
20
|
+
result.body.should == json
|
21
|
+
end
|
22
|
+
|
23
|
+
it "doesn't change anything else" do
|
24
|
+
result = decoder.call(env)
|
25
|
+
result.status.should == 200
|
26
|
+
result.headers.should == {"Content-Type" => "application/json"}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "for non-JSON responses" do
|
31
|
+
it "doesn't decode" do
|
32
|
+
result.headers = {"Content-Type" => "text/html"}
|
33
|
+
decoder.call(env).body.should == MultiJson.dump(json)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchApi::InternalMiddleware::ResponseFilter do
|
4
|
+
let(:app) { stub("app", call: result) }
|
5
|
+
let(:surpressor) { BatchApi::InternalMiddleware::ResponseFilter.new(app) }
|
6
|
+
let(:env) { {
|
7
|
+
op: stub("operation", options: {"silent" => true})
|
8
|
+
} }
|
9
|
+
|
10
|
+
let(:result) {
|
11
|
+
BatchApi::Response.new([
|
12
|
+
200,
|
13
|
+
{"Content-Type" => "application/json"},
|
14
|
+
["{}"]
|
15
|
+
])
|
16
|
+
}
|
17
|
+
|
18
|
+
describe "#call" do
|
19
|
+
context "for results with silent" do
|
20
|
+
context "for successful (200-299) results" do
|
21
|
+
it "empties the response so its as_json is empty" do
|
22
|
+
surpressor.call(env)
|
23
|
+
result.as_json.should == {}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "for non-successful responses" do
|
28
|
+
it "doesn't change anything else" do
|
29
|
+
result.status = 301
|
30
|
+
expect {
|
31
|
+
surpressor.call(env)
|
32
|
+
}.not_to change(result, :to_s)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "for results without silent" do
|
38
|
+
before :each do
|
39
|
+
env[:op].options[:silent] = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
context "for successful (200-299) results" do
|
43
|
+
it "does nothing" do
|
44
|
+
expect {
|
45
|
+
surpressor.call(env)
|
46
|
+
}.not_to change(result, :to_s)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "for non-successful responses" do
|
51
|
+
it "doesn't change anything else" do
|
52
|
+
result.status = 301
|
53
|
+
expect {
|
54
|
+
surpressor.call(env)
|
55
|
+
}.not_to change(result, :to_s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchApi::InternalMiddleware do
|
4
|
+
class FakeBuilder
|
5
|
+
attr_accessor :middlewares
|
6
|
+
|
7
|
+
def initialize(&block)
|
8
|
+
@middlewares = []
|
9
|
+
instance_eval(&block) if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
def use(middleware, *args)
|
13
|
+
@middlewares << [middleware, args]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:builder) { FakeBuilder.new }
|
18
|
+
|
19
|
+
it "builds an empty default global middleware" do
|
20
|
+
builder.instance_eval(
|
21
|
+
&BatchApi::InternalMiddleware::DEFAULT_BATCH_MIDDLEWARE
|
22
|
+
)
|
23
|
+
builder.middlewares.should be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "internal middleware defaults" do
|
27
|
+
before :each do
|
28
|
+
builder.instance_eval(
|
29
|
+
&BatchApi::InternalMiddleware::DEFAULT_OPERATION_MIDDLEWARE
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "builds a per-op middleware with the response silencer" do
|
34
|
+
builder.middlewares[0].should ==
|
35
|
+
[BatchApi::InternalMiddleware::ResponseFilter, []]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "builds a per-op middleware with the JSON decoder" do
|
39
|
+
builder.middlewares[1].should ==
|
40
|
+
[BatchApi::InternalMiddleware::DecodeJsonBody, []]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".batch_stack" do
|
45
|
+
# we can't use stubs inside the procs since they're instance_eval'd
|
46
|
+
let(:global_config) { Proc.new { use "Global" } }
|
47
|
+
let(:strategy) { stub("strategy") }
|
48
|
+
let(:processor) { stub("processor", strategy: strategy) }
|
49
|
+
let(:stack) { BatchApi::InternalMiddleware.batch_stack(processor) }
|
50
|
+
|
51
|
+
before :each do
|
52
|
+
BatchApi.config.stub(:batch_middleware).and_return(global_config)
|
53
|
+
stub_const("Middleware::Builder", FakeBuilder)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "builds the stack with the right number of wares" do
|
57
|
+
stack.middlewares.length.should == 2
|
58
|
+
end
|
59
|
+
|
60
|
+
it "builds a middleware stack starting with the configured global wares" do
|
61
|
+
stack.middlewares[0].first.should == "Global"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "inserts the appropriate strategy from the processor" do
|
65
|
+
stack.middlewares[1].first.should == strategy
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe ".operation_stack" do
|
70
|
+
# we can't use stubs inside the procs since they're instance_eval'd
|
71
|
+
let(:op_config) { Proc.new { use "Op" } }
|
72
|
+
let(:stack) { BatchApi::InternalMiddleware.operation_stack }
|
73
|
+
|
74
|
+
before :each do
|
75
|
+
BatchApi.config.stub(:operation_middleware).and_return(op_config)
|
76
|
+
stub_const("Middleware::Builder", FakeBuilder)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "builds the stack with the right number of wares" do
|
80
|
+
stack.middlewares.length.should == 2
|
81
|
+
end
|
82
|
+
|
83
|
+
it "builds a middleware stack including the configured per-op wares" do
|
84
|
+
stack.middlewares[0].first.should == "Op"
|
85
|
+
end
|
86
|
+
|
87
|
+
it "builds a middleware stack ending with the executor" do
|
88
|
+
stack.middlewares[1].first.should == BatchApi::Processor::Executor
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'batch_api/operation'
|
3
|
+
|
4
|
+
describe BatchApi::Operation::Rack do
|
5
|
+
let(:op_params) { {
|
6
|
+
"method" => "POST",
|
7
|
+
# this matches a route in our dummy application
|
8
|
+
"url" => "/endpoint?foo=baz",
|
9
|
+
"params" => {a: 2},
|
10
|
+
"headers" => {"foo" => "bar"}
|
11
|
+
} }
|
12
|
+
|
13
|
+
# for env, see bottom of file - it's long
|
14
|
+
let(:operation) { BatchApi::Operation::Rack.new(op_params, env, app) }
|
15
|
+
let(:app) { stub("application", call: [200, {}, ["foo"]]) }
|
16
|
+
|
17
|
+
describe "accessors" do
|
18
|
+
[
|
19
|
+
:method, :url, :params, :headers,
|
20
|
+
:env, :app, :result, :options
|
21
|
+
].each do |a|
|
22
|
+
attr = a
|
23
|
+
it "has an accessor for #{attr}" do
|
24
|
+
value = stub
|
25
|
+
operation.send("#{attr}=", value)
|
26
|
+
operation.send(attr).should == value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#initialize" do
|
32
|
+
["method", "url", "params", "headers"].each do |a|
|
33
|
+
attr = a
|
34
|
+
it "extracts the #{attr} information from the operation params" do
|
35
|
+
operation.send(attr).should == op_params[attr]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sets options to the op" do
|
40
|
+
operation.options.should == op_params
|
41
|
+
end
|
42
|
+
|
43
|
+
it "defaults params to {} if not provided" do
|
44
|
+
op = BatchApi::Operation::Rack.new(op_params.except("params"), env, app)
|
45
|
+
op.params.should == {}
|
46
|
+
end
|
47
|
+
|
48
|
+
it "defaults headers to {} if not provided" do
|
49
|
+
op = BatchApi::Operation::Rack.new(op_params.except("headers"), env, app)
|
50
|
+
op.headers.should == {}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "does a deep dup of the env" do
|
54
|
+
operation.env.should == env
|
55
|
+
|
56
|
+
flat_env = env.to_a.flatten
|
57
|
+
operation.env.to_a.flatten.each_with_index do |obj, index|
|
58
|
+
# this is a rough test for deep dup -- make sure the objects
|
59
|
+
# that aren't symbols aren't actually the same objects in memory
|
60
|
+
if obj.is_a?(Hash) || obj.is_a?(Array)
|
61
|
+
obj.object_id.should_not == flat_env[index].object_id
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "raises a MalformedOperationError if method or URL are missing" do
|
67
|
+
no_method = op_params.dup.tap {|o| o.delete("method") }
|
68
|
+
expect {
|
69
|
+
BatchApi::Operation::Rack.new(no_method, env, app)
|
70
|
+
}.to raise_exception(BatchApi::Errors::MalformedOperationError)
|
71
|
+
|
72
|
+
no_url = op_params.dup.tap {|o| o.delete("url") }
|
73
|
+
expect {
|
74
|
+
BatchApi::Operation::Rack.new(no_url, env, app)
|
75
|
+
}.to raise_exception(BatchApi::Errors::MalformedOperationError)
|
76
|
+
|
77
|
+
nothing = op_params.dup.tap {|o| o.delete("url"); o.delete("method") }
|
78
|
+
expect {
|
79
|
+
BatchApi::Operation::Rack.new(nothing, env, app)
|
80
|
+
}.to raise_exception(BatchApi::Errors::MalformedOperationError)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#process_env" do
|
85
|
+
let(:processed_env) { operation.tap {|o| o.process_env}.env }
|
86
|
+
|
87
|
+
it "merges any headers in in the right format" do
|
88
|
+
key = "HTTP_FOO" # as defined above in op_params
|
89
|
+
|
90
|
+
processed_env[key].should_not == env[key]
|
91
|
+
# in this case, it's a batch controller
|
92
|
+
processed_env[key].should == op_params["headers"]["foo"]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "preserves existing headers" do
|
96
|
+
processed_env["HTTP_PREVIOUS_HEADERS"].should == env["HTTP_PREVIOUS_HEADERS"]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "updates the method" do
|
100
|
+
key = "REQUEST_METHOD"
|
101
|
+
processed_env[key].should_not == env[key]
|
102
|
+
processed_env[key].should == "POST"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "updates the REQUEST_URI" do
|
106
|
+
key = "REQUEST_URI"
|
107
|
+
processed_env[key].should_not == env[key]
|
108
|
+
processed_env[key].should == env["REQUEST_URI"].gsub(/\/batch.*/, op_params["url"])
|
109
|
+
end
|
110
|
+
|
111
|
+
it "updates the REQUEST_PATH with the path component (w/o params)" do
|
112
|
+
key = "REQUEST_PATH"
|
113
|
+
processed_env[key].should_not == env[key]
|
114
|
+
processed_env[key].should == op_params["url"].split("?").first
|
115
|
+
end
|
116
|
+
|
117
|
+
it "updates the original fullpath" do
|
118
|
+
key = "ORIGINAL_FULLPATH"
|
119
|
+
processed_env[key].should_not == env[key]
|
120
|
+
processed_env[key].should == op_params["url"]
|
121
|
+
end
|
122
|
+
|
123
|
+
it "updates the PATH_INFO" do
|
124
|
+
key = "PATH_INFO"
|
125
|
+
processed_env[key].should_not == env[key]
|
126
|
+
processed_env[key].should == op_params["url"]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "updates the rack query string" do
|
130
|
+
key = "rack.request.query_string"
|
131
|
+
processed_env[key].should_not == env[key]
|
132
|
+
processed_env[key].should == op_params["url"].split("?").last
|
133
|
+
end
|
134
|
+
|
135
|
+
it "updates the QUERY_STRING" do
|
136
|
+
key = "QUERY_STRING"
|
137
|
+
processed_env[key].should_not == env[key]
|
138
|
+
processed_env[key].should == op_params["url"].split("?").last
|
139
|
+
end
|
140
|
+
|
141
|
+
it "updates the form hash" do
|
142
|
+
key = "rack.request.form_hash"
|
143
|
+
processed_env[key].should_not == env[key]
|
144
|
+
processed_env[key].should == op_params["params"]
|
145
|
+
end
|
146
|
+
|
147
|
+
context "query_hash" do
|
148
|
+
it "sets it to params for a GET" do
|
149
|
+
operation.method = "get"
|
150
|
+
processed_env = operation.tap {|o| o.process_env}.env
|
151
|
+
key = "rack.request.query_hash"
|
152
|
+
processed_env[key].should_not == env[key]
|
153
|
+
processed_env[key].should == op_params["params"]
|
154
|
+
end
|
155
|
+
|
156
|
+
it "sets it to nil for a POST" do
|
157
|
+
key = "rack.request.query_hash"
|
158
|
+
processed_env[key].should_not == env[key]
|
159
|
+
processed_env[key].should be_nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "#execute" do
|
165
|
+
context "when it works" do
|
166
|
+
let(:result) { [
|
167
|
+
200,
|
168
|
+
{header: "footer"},
|
169
|
+
stub(body: "{\"data\":2}", cookies: nil)
|
170
|
+
] }
|
171
|
+
let(:processed_env) { stub }
|
172
|
+
|
173
|
+
before :each do
|
174
|
+
operation.stub(:process_env) { operation.env = processed_env }
|
175
|
+
end
|
176
|
+
|
177
|
+
it "executes the call with the application" do
|
178
|
+
app.should_receive(:call).with(processed_env)
|
179
|
+
operation.execute
|
180
|
+
end
|
181
|
+
|
182
|
+
it "returns a BatchAPI::Response made from the result" do
|
183
|
+
response = stub
|
184
|
+
app.stub(:call).and_return(result)
|
185
|
+
BatchApi::Response.should_receive(:new).with(result).and_return(response)
|
186
|
+
operation.execute.should == response
|
187
|
+
end
|
188
|
+
|
189
|
+
it "returns a BatchApi::Response from an ErrorWrapper for errors" do
|
190
|
+
err = StandardError.new
|
191
|
+
result, rendered, response = stub, stub, stub
|
192
|
+
b_err = stub("batch error", render: rendered)
|
193
|
+
|
194
|
+
# simulate the error
|
195
|
+
app.stub(:call).and_raise(err)
|
196
|
+
# we'll create the BatchError
|
197
|
+
BatchApi::ErrorWrapper.should_receive(:new).with(err).and_return(b_err)
|
198
|
+
# render that as the response
|
199
|
+
BatchApi::Response.should_receive(:new).with(rendered).and_return(response)
|
200
|
+
# and return the response overall
|
201
|
+
operation.execute.should == response
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
let(:env) {
|
207
|
+
{
|
208
|
+
"CONTENT_LENGTH"=>"10",
|
209
|
+
"CONTENT_TYPE"=>"application/x-www-form-urlencoded",
|
210
|
+
"GATEWAY_INTERFACE"=>"CGI/1.1",
|
211
|
+
"PATH_INFO"=>"/foo",
|
212
|
+
"QUERY_STRING"=>"",
|
213
|
+
"REMOTE_ADDR"=>"127.0.0.1",
|
214
|
+
"REMOTE_HOST"=>"1035.spotilocal.com",
|
215
|
+
"REQUEST_METHOD"=>"REPORT",
|
216
|
+
"REQUEST_URI"=>"http://localhost:3000/batch",
|
217
|
+
"SCRIPT_NAME"=>"",
|
218
|
+
"SERVER_NAME"=>"localhost",
|
219
|
+
"SERVER_PORT"=>"3000",
|
220
|
+
"SERVER_PROTOCOL"=>"HTTP/1.1",
|
221
|
+
"SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2012-02-16)",
|
222
|
+
"HTTP_USER_AGENT"=>"curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
|
223
|
+
"HTTP_HOST"=>"localhost:3000",
|
224
|
+
"HTTP_ACCEPT"=>"*/*",
|
225
|
+
"HTTP_PREVIOUS_HEADERS" => "value",
|
226
|
+
"rack.version"=>[1,1],
|
227
|
+
"rack.input"=>StringIO.new("{\"ops\":{}}"),
|
228
|
+
"rack.errors"=>$stderr,
|
229
|
+
"rack.multithread"=>false,
|
230
|
+
"rack.multiprocess"=>false,
|
231
|
+
"rack.run_once"=>false,
|
232
|
+
"rack.url_scheme"=>"http",
|
233
|
+
"HTTP_VERSION"=>"HTTP/1.1",
|
234
|
+
"REQUEST_PATH"=>"/batch",
|
235
|
+
"ORIGINAL_FULLPATH"=>"/batch",
|
236
|
+
"rack.request.form_input"=>StringIO.new("{\"ops\":{}}"),
|
237
|
+
"rack.request.form_hash"=>{"{\"ops\":{}}"=>nil},
|
238
|
+
"rack.request.form_vars"=>"{\"ops\":{}}",
|
239
|
+
"rack.request.query_string"=>"",
|
240
|
+
"rack.request.query_hash"=>{}
|
241
|
+
}
|
242
|
+
}
|
243
|
+
end
|