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,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'batch_api/operation'
|
3
|
+
|
4
|
+
describe BatchApi::Operation::Rails 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::Rails.new(op_params, env, app) }
|
15
|
+
let(:app) { stub("application", call: [200, {}, ["foo"]]) }
|
16
|
+
let(:path_params) { {controller: "batch_api/batch", action: "batch"} }
|
17
|
+
let(:mixed_params) { op_params["params"].merge(path_params) }
|
18
|
+
|
19
|
+
before :each do
|
20
|
+
::Rails.application.routes.stub(:recognize_path).and_return(path_params)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#initialize" do
|
24
|
+
it "merges in the Rails path params" do
|
25
|
+
::Rails.application.routes.should_receive(:recognize_path).with(
|
26
|
+
op_params["url"],
|
27
|
+
op_params
|
28
|
+
).and_return(path_params)
|
29
|
+
|
30
|
+
operation.params.should include(path_params)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "doesn't change the params if the path isn't recognized" do
|
34
|
+
::Rails.application.routes.stub(:recognize_path).and_raise(StandardError)
|
35
|
+
operation.params.should == op_params["params"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#process_env" do
|
40
|
+
let(:processed_env) { operation.tap {|o| o.process_env}.env }
|
41
|
+
|
42
|
+
it "updates the ActionDispatch params" do
|
43
|
+
key = "action_dispatch.request.parameters"
|
44
|
+
processed_env[key].should_not == env[key]
|
45
|
+
processed_env[key].should == mixed_params
|
46
|
+
end
|
47
|
+
|
48
|
+
it "updates the ActionDispatch request params" do
|
49
|
+
key = "action_dispatch.request.request_parameters"
|
50
|
+
processed_env[key].should_not == env[key]
|
51
|
+
processed_env[key].should == mixed_params
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
let(:env) {
|
56
|
+
{
|
57
|
+
"CONTENT_LENGTH"=>"10",
|
58
|
+
"CONTENT_TYPE"=>"application/x-www-form-urlencoded",
|
59
|
+
"GATEWAY_INTERFACE"=>"CGI/1.1",
|
60
|
+
"PATH_INFO"=>"/foo",
|
61
|
+
"QUERY_STRING"=>"",
|
62
|
+
"REMOTE_ADDR"=>"127.0.0.1",
|
63
|
+
"REMOTE_HOST"=>"1035.spotilocal.com",
|
64
|
+
"REQUEST_METHOD"=>"REPORT",
|
65
|
+
"REQUEST_URI"=>"http://localhost:3000/batch",
|
66
|
+
"SCRIPT_NAME"=>"",
|
67
|
+
"SERVER_NAME"=>"localhost",
|
68
|
+
"SERVER_PORT"=>"3000",
|
69
|
+
"SERVER_PROTOCOL"=>"HTTP/1.1",
|
70
|
+
"SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2012-02-16)",
|
71
|
+
"HTTP_USER_AGENT"=>"curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
|
72
|
+
"HTTP_HOST"=>"localhost:3000",
|
73
|
+
"HTTP_ACCEPT"=>"*/*",
|
74
|
+
"HTTP_PREVIOUS_HEADERS" => "value",
|
75
|
+
"rack.version"=>[1,1],
|
76
|
+
"rack.input"=>StringIO.new("{\"ops\":{}}"),
|
77
|
+
"rack.errors"=>$stderr,
|
78
|
+
"rack.multithread"=>false,
|
79
|
+
"rack.multiprocess"=>false,
|
80
|
+
"rack.run_once"=>false,
|
81
|
+
"rack.url_scheme"=>"http",
|
82
|
+
"HTTP_VERSION"=>"HTTP/1.1",
|
83
|
+
"REQUEST_PATH"=>"/batch",
|
84
|
+
"ORIGINAL_FULLPATH"=>"/batch",
|
85
|
+
"action_dispatch.routes"=>Rails.application.routes,
|
86
|
+
"action_dispatch.parameter_filter"=>[:password],
|
87
|
+
"action_dispatch.secret_token"=>"fc6fbc81b3204410da8389",
|
88
|
+
"action_dispatch.show_exceptions"=>true,
|
89
|
+
"action_dispatch.show_detailed_exceptions"=>true,
|
90
|
+
"action_dispatch.logger"=>Rails.logger,
|
91
|
+
"action_dispatch.backtrace_cleaner"=>nil,
|
92
|
+
"action_dispatch.request_id"=>"2e7c988bea73e13dca4fac059a1bb187",
|
93
|
+
"action_dispatch.remote_ip"=>"127.0.0.1",
|
94
|
+
"action_dispatch.request.content_type"=>"application/x-www-form-urlencoded",
|
95
|
+
"action_dispatch.request.path_parameters"=> {},
|
96
|
+
"rack.request.query_string"=>"",
|
97
|
+
"rack.request.query_hash"=>{}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'batch_api/processor/executor'
|
3
|
+
|
4
|
+
describe BatchApi::Processor::Executor do
|
5
|
+
|
6
|
+
let(:app) { stub("app", call: stub) }
|
7
|
+
let(:executor) { BatchApi::Processor::Executor.new(app) }
|
8
|
+
let(:result) { stub("result") }
|
9
|
+
let(:op) { stub("operation", execute: result) }
|
10
|
+
let(:env) { {op: op} }
|
11
|
+
|
12
|
+
describe "#call" do
|
13
|
+
it "executes the operation" do
|
14
|
+
op.should_receive(:execute)
|
15
|
+
executor.call(env)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns the result" do
|
19
|
+
executor.call(env).should == result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchApi::Processor::Sequential do
|
4
|
+
|
5
|
+
let(:app) { stub("app", call: stub) }
|
6
|
+
let(:sequential) { BatchApi::Processor::Sequential.new(app) }
|
7
|
+
|
8
|
+
describe "#call" do
|
9
|
+
let(:call_results) { 3.times.collect {|i| stub("called #{i}") } }
|
10
|
+
let(:env) { {
|
11
|
+
ops: 3.times.collect {|i| stub("op #{i}") }
|
12
|
+
} }
|
13
|
+
let(:op_middleware) { stub("middleware", call: {}) }
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
BatchApi::InternalMiddleware.
|
17
|
+
stub(:operation_stack).and_return(op_middleware)
|
18
|
+
op_middleware.stub(:call).and_return(*call_results)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "creates an operation middleware stack and calls it for each op" do
|
22
|
+
env[:ops].each {|op|
|
23
|
+
op_middleware.should_receive(:call).
|
24
|
+
with(hash_including(op: op)).ordered
|
25
|
+
}
|
26
|
+
sequential.call(env)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "includes the rest of the env in the calls" do
|
30
|
+
op_middleware.should_receive(:call).
|
31
|
+
with(hash_including(env)).exactly(3).times
|
32
|
+
sequential.call(env)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns the results of the calls" do
|
36
|
+
sequential.call(env).should == call_results
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchApi::Processor do
|
4
|
+
|
5
|
+
let(:ops) { [ {"url" => "/endpoint", "method" => "get"} ] }
|
6
|
+
let(:options) { { "sequential" => true } }
|
7
|
+
let(:env) { {
|
8
|
+
"CONTENT_TYPE"=>"application/x-www-form-urlencoded",
|
9
|
+
"GATEWAY_INTERFACE"=>"CGI/1.1",
|
10
|
+
"PATH_INFO"=>"/foo",
|
11
|
+
"QUERY_STRING"=>"",
|
12
|
+
"REMOTE_ADDR"=>"127.0.0.1",
|
13
|
+
"REMOTE_HOST"=>"1035.spotilocal.com",
|
14
|
+
"REQUEST_METHOD"=>"REPORT",
|
15
|
+
"REQUEST_URI"=>"http://localhost:3000/batch",
|
16
|
+
"SCRIPT_NAME"=>"",
|
17
|
+
"rack.input" => StringIO.new,
|
18
|
+
"rack.errors" => StringIO.new,
|
19
|
+
"SERVER_NAME"=>"localhost",
|
20
|
+
"SERVER_PORT"=>"3000",
|
21
|
+
"SERVER_PROTOCOL"=>"HTTP/1.1",
|
22
|
+
"SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2012-02-16)",
|
23
|
+
"HTTP_USER_AGENT"=>"curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21",
|
24
|
+
"HTTP_HOST"=>"localhost:3000"
|
25
|
+
} }
|
26
|
+
|
27
|
+
let(:request) {
|
28
|
+
Rack::Request.new(env).tap do |r|
|
29
|
+
r.stub(:params).and_return({}.merge("ops" => ops).merge(options))
|
30
|
+
end
|
31
|
+
}
|
32
|
+
let(:app) { stub("application", call: [200, {}, ["foo"]]) }
|
33
|
+
let(:processor) { BatchApi::Processor.new(request, app) }
|
34
|
+
|
35
|
+
describe "#initialize" do
|
36
|
+
# this may be brittle...consider refactoring?
|
37
|
+
it "turns the ops params into processed operations at #ops" do
|
38
|
+
# simulate receiving several operations
|
39
|
+
klass = stub("op class")
|
40
|
+
BatchApi::Processor.stub(:operation_klass).and_return(klass)
|
41
|
+
operation_objects = 3.times.collect { stub("operation object") }
|
42
|
+
operation_params = 3.times.collect do |i|
|
43
|
+
stub("raw operation").tap do |o|
|
44
|
+
klass.should_receive(:new)
|
45
|
+
.with(o, env, app).and_return(operation_objects[i])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
request.params["ops"] = operation_params
|
50
|
+
BatchApi::Processor.new(request, app).ops.should == operation_objects
|
51
|
+
end
|
52
|
+
|
53
|
+
it "makes the options available" do
|
54
|
+
BatchApi::Processor.new(request, app).options.should == options
|
55
|
+
end
|
56
|
+
|
57
|
+
it "makes the app available" do
|
58
|
+
BatchApi::Processor.new(request, app).app.should == app
|
59
|
+
end
|
60
|
+
|
61
|
+
context "error conditions" do
|
62
|
+
it "(currently) throws an error if sequential is not true" do
|
63
|
+
request.params.delete("sequential")
|
64
|
+
expect {
|
65
|
+
BatchApi::Processor.new(request, app)
|
66
|
+
}.to raise_exception(BatchApi::Errors::BadOptionError)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "raise a OperationLimitExceeded error if too many ops provided" do
|
70
|
+
ops = (BatchApi.config.limit + 1).to_i.times.collect {|i| i}
|
71
|
+
request.params["ops"] = ops
|
72
|
+
expect {
|
73
|
+
BatchApi::Processor.new(request, app)
|
74
|
+
}.to raise_exception(BatchApi::Errors::OperationLimitExceeded)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "raises a NoOperationError if operations.blank?" do
|
78
|
+
request.params["ops"] = nil
|
79
|
+
expect {
|
80
|
+
BatchApi::Processor.new(request, app)
|
81
|
+
}.to raise_exception(BatchApi::Errors::NoOperationsError)
|
82
|
+
request.params["ops"] = []
|
83
|
+
expect {
|
84
|
+
BatchApi::Processor.new(request, app)
|
85
|
+
}.to raise_exception(BatchApi::Errors::NoOperationsError)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#strategy" do
|
91
|
+
it "returns BatchApi::Processor::Sequential" do
|
92
|
+
processor.strategy.should == BatchApi::Processor::Sequential
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#execute!" do
|
97
|
+
let(:result) { stub("result") }
|
98
|
+
let(:stack) { stub("stack", call: result) }
|
99
|
+
let(:middleware_env) { {
|
100
|
+
ops: processor.ops, # the processed Operation objects
|
101
|
+
rack_env: env,
|
102
|
+
rack_app: app,
|
103
|
+
options: options
|
104
|
+
} }
|
105
|
+
|
106
|
+
before :each do
|
107
|
+
BatchApi::InternalMiddleware.stub(:batch_stack).and_return(stack)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "calls an internal middleware stacks with the appropriate data" do
|
111
|
+
stack.should_receive(:call).with(middleware_env)
|
112
|
+
processor.execute!
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns the formatted result of the strategy" do
|
116
|
+
stack.stub(:call).and_return(stubby = stub)
|
117
|
+
processor.execute!["results"].should == stubby
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe ".operation_klass" do
|
122
|
+
it "returns BatchApi::Operation::Rack if !Rails" do
|
123
|
+
BatchApi.stub(:rails?).and_return(false)
|
124
|
+
BatchApi::Processor.operation_klass.should ==
|
125
|
+
BatchApi::Operation::Rack
|
126
|
+
end
|
127
|
+
|
128
|
+
it "returns BatchApi::Operation::Rails if Rails" do
|
129
|
+
BatchApi.stub(:rails?).and_return(true)
|
130
|
+
BatchApi::Processor.operation_klass.should ==
|
131
|
+
BatchApi::Operation::Rails
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe BatchApi::RackMiddleware do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "allows access to the BatchApi configuration" do
|
6
|
+
limit = rand * 100
|
7
|
+
middleware = BatchApi::RackMiddleware.new(stub("app")) do |conf|
|
8
|
+
conf.limit = limit
|
9
|
+
end
|
10
|
+
BatchApi.config.limit.should == limit
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#call" do
|
15
|
+
let(:endpoint) { "/foo/bar" }
|
16
|
+
let(:verb) { "run" }
|
17
|
+
let(:app) { stub("app") }
|
18
|
+
|
19
|
+
let(:middleware) {
|
20
|
+
BatchApi::RackMiddleware.new(app) do |conf|
|
21
|
+
conf.endpoint = endpoint
|
22
|
+
conf.verb = verb
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
context "if it's a batch call" do
|
27
|
+
let(:env) { {
|
28
|
+
"PATH_INFO" => endpoint,
|
29
|
+
"REQUEST_METHOD" => verb.upcase,
|
30
|
+
# other stuff
|
31
|
+
"CONTENT_TYPE"=>"application/x-www-form-urlencoded",
|
32
|
+
"GATEWAY_INTERFACE"=>"CGI/1.1",
|
33
|
+
"QUERY_STRING"=>"",
|
34
|
+
"REMOTE_ADDR"=>"127.0.0.1",
|
35
|
+
"REMOTE_HOST"=>"1035.spotilocal.com",
|
36
|
+
"REQUEST_URI"=>"http://localhost:3000/batch",
|
37
|
+
"SCRIPT_NAME"=>"",
|
38
|
+
"rack.input" => StringIO.new,
|
39
|
+
"rack.errors" => StringIO.new,
|
40
|
+
"SERVER_NAME"=>"localhost",
|
41
|
+
"SERVER_PORT"=>"3000",
|
42
|
+
"SERVER_PROTOCOL"=>"HTTP/1.1",
|
43
|
+
"SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.9.3/2012-02-16)",
|
44
|
+
"HTTP_USER_AGENT"=>"curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
|
45
|
+
"HTTP_HOST"=>"localhost:3000"
|
46
|
+
} }
|
47
|
+
|
48
|
+
let(:request) { Rack::Request.new(env) }
|
49
|
+
let(:result) { {a: 2, b: {c: 3}} }
|
50
|
+
let(:processor) { stub("processor", :execute! => result) }
|
51
|
+
|
52
|
+
before :each do
|
53
|
+
BatchApi::Processor.stub(:new).and_return(processor)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "processes the batch request" do
|
57
|
+
Rack::Request.stub(:new).with(env).and_return(request)
|
58
|
+
BatchApi::Processor.should_receive(:new).with(request, app).and_return(processor)
|
59
|
+
middleware.call(env)
|
60
|
+
end
|
61
|
+
|
62
|
+
context "for a successful set of calls" do
|
63
|
+
it "returns the JSON-encoded result as the body" do
|
64
|
+
output = middleware.call(env)
|
65
|
+
output[2].should == [MultiJson.dump(result)]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns a 200" do
|
69
|
+
middleware.call(env)[0].should == 200
|
70
|
+
end
|
71
|
+
|
72
|
+
it "sets the content type" do
|
73
|
+
middleware.call(env)[1].should include("Content-Type" => "application/json")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "for BatchApi errors" do
|
78
|
+
it "returns a rendered ErrorWrapper" do
|
79
|
+
err, result = StandardError.new, stub
|
80
|
+
error = stub("error object", render: result)
|
81
|
+
BatchApi::Processor.stub(:new).and_raise(err)
|
82
|
+
BatchApi::ErrorWrapper.should_receive(:new).with(err).and_return(
|
83
|
+
error
|
84
|
+
)
|
85
|
+
middleware.call(env).should == result
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "if it's not a batch request" do
|
91
|
+
let(:env) { {
|
92
|
+
"PATH_INFO" => "/not/batch",
|
93
|
+
"REQUEST_METHOD" => verb.upcase
|
94
|
+
} }
|
95
|
+
|
96
|
+
it "just calls the app onward and returns the result" do
|
97
|
+
output = stub("output")
|
98
|
+
app.should_receive(:call).with(env).and_return(output)
|
99
|
+
middleware.call(env)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'batch_api/response'
|
3
|
+
|
4
|
+
describe BatchApi::Response do
|
5
|
+
|
6
|
+
let(:raw_response) { [200, {}, ["ab", "cd", "ef"]] }
|
7
|
+
let(:response) { BatchApi::Response.new(raw_response) }
|
8
|
+
|
9
|
+
[:status, :body, :headers].each do |attr|
|
10
|
+
local_attr = attr
|
11
|
+
it "has an accessor for #{local_attr}" do
|
12
|
+
response.should respond_to(local_attr)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
it "sets status to the HTTP status code" do
|
18
|
+
response.status.should == raw_response.first
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets body to the HTTP body turned into a string" do
|
22
|
+
response.body.should == raw_response[2].join
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets headers to the HTTP headers" do
|
26
|
+
response.headers.should == raw_response[1]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#as_json" do
|
31
|
+
it "creates the expected hash" do
|
32
|
+
response.as_json.should == {
|
33
|
+
body: response.body,
|
34
|
+
status: response.status,
|
35
|
+
headers: response.headers
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "accepts options" do
|
40
|
+
response.as_json(foo: :bar).should_not be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "leaves out items that are blank" do
|
44
|
+
response.status = response.body = nil
|
45
|
+
response.as_json.should == {headers: raw_response[1]}
|
46
|
+
end
|
47
|
+
|
48
|
+
it "includes items that are false" do
|
49
|
+
response.body = false
|
50
|
+
response.as_json[:body].should == false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|