stitches 3.0.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +126 -0
- data/README.md +220 -0
- data/Rakefile +13 -0
- data/lib/stitches.rb +3 -0
- data/lib/stitches/api_generator.rb +97 -0
- data/lib/stitches/api_key.rb +59 -0
- data/lib/stitches/api_version_constraint.rb +32 -0
- data/lib/stitches/configuration.rb +77 -0
- data/lib/stitches/error.rb +9 -0
- data/lib/stitches/errors.rb +101 -0
- data/lib/stitches/generator_files/app/controllers/api.rb +2 -0
- data/lib/stitches/generator_files/app/controllers/api/api_controller.rb +19 -0
- data/lib/stitches/generator_files/app/controllers/api/v1.rb +2 -0
- data/lib/stitches/generator_files/app/controllers/api/v1/pings_controller.rb +20 -0
- data/lib/stitches/generator_files/app/controllers/api/v2.rb +2 -0
- data/lib/stitches/generator_files/app/controllers/api/v2/pings_controller.rb +20 -0
- data/lib/stitches/generator_files/app/models/api_client.rb +2 -0
- data/lib/stitches/generator_files/config/initializers/stitches.rb +14 -0
- data/lib/stitches/generator_files/db/migrate/create_api_clients.rb +11 -0
- data/lib/stitches/generator_files/db/migrate/enable_uuid_ossp_extension.rb +5 -0
- data/lib/stitches/generator_files/lib/tasks/generate_api_key.rake +10 -0
- data/lib/stitches/generator_files/spec/acceptance/ping_v1_spec.rb +46 -0
- data/lib/stitches/generator_files/spec/features/api_spec.rb +96 -0
- data/lib/stitches/railtie.rb +9 -0
- data/lib/stitches/render_timestamps_in_iso8601_in_json.rb +9 -0
- data/lib/stitches/spec.rb +4 -0
- data/lib/stitches/spec/api_clients.rb +5 -0
- data/lib/stitches/spec/be_iso_8601_utc_encoded.rb +10 -0
- data/lib/stitches/spec/have_api_error.rb +50 -0
- data/lib/stitches/spec/test_headers.rb +51 -0
- data/lib/stitches/valid_mime_type.rb +32 -0
- data/lib/stitches/version.rb +3 -0
- data/lib/stitches/whitelisting_middleware.rb +29 -0
- data/lib/stitches_norailtie.rb +17 -0
- data/spec/api_key_spec.rb +200 -0
- data/spec/api_version_constraint_spec.rb +33 -0
- data/spec/configuration_spec.rb +105 -0
- data/spec/errors_spec.rb +99 -0
- data/spec/spec/have_api_error_spec.rb +78 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/valid_mime_type_spec.rb +166 -0
- data/stitches.gemspec +24 -0
- metadata +168 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Stitches::ApiVersionConstraint do
|
4
|
+
let(:version) { 2 }
|
5
|
+
let(:request) { double("request", headers: headers) }
|
6
|
+
|
7
|
+
subject(:constraint) { described_class.new(version) }
|
8
|
+
|
9
|
+
context "no accept header" do
|
10
|
+
let(:headers) { {} }
|
11
|
+
it "doesn't match" do
|
12
|
+
expect(constraint.matches?(request)).to eq(false)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
context "accept header missing version" do
|
16
|
+
let(:headers) { { accept: "application/json" } }
|
17
|
+
it "doesn't match" do
|
18
|
+
expect(constraint.matches?(request)).to eq(false)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
context "accept header has wrong version" do
|
22
|
+
let(:headers) { { accept: "application/json; version=1" } }
|
23
|
+
it "doesn't match" do
|
24
|
+
expect(constraint.matches?(request)).to eq(false)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context "accept header has correct version" do
|
28
|
+
let(:headers) { { accept: "application/json; version=2" } }
|
29
|
+
it "matcheds" do
|
30
|
+
expect(constraint.matches?(request)).to eq(true)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Stitches::Configuration do
|
4
|
+
before do
|
5
|
+
Stitches.configuration.reset_to_defaults!
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "global configuration" do
|
9
|
+
let(:whitelist_regexp) { %r{foo} }
|
10
|
+
let(:custom_http_auth_scheme) { "Blah" }
|
11
|
+
let(:env_var_to_hold_api_client_primary_key) { "FOOBAR" }
|
12
|
+
|
13
|
+
it "can be configured globally" do
|
14
|
+
Stitches.configure do |config|
|
15
|
+
config.whitelist_regexp = whitelist_regexp
|
16
|
+
config.custom_http_auth_scheme = custom_http_auth_scheme
|
17
|
+
config.env_var_to_hold_api_client_primary_key = env_var_to_hold_api_client_primary_key
|
18
|
+
end
|
19
|
+
|
20
|
+
expect(Stitches.configuration.whitelist_regexp).to eq(whitelist_regexp)
|
21
|
+
expect(Stitches.configuration.custom_http_auth_scheme).to eq(custom_http_auth_scheme)
|
22
|
+
expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq(env_var_to_hold_api_client_primary_key)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "defaults to nil for whitelist_regexp" do
|
26
|
+
expect(Stitches.configuration.whitelist_regexp).to be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "sets a default for env_var_to_hold_api_client_primary_key" do
|
30
|
+
expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq("STITCHES_API_CLIENT_ID")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "blows up if you try to use custom_http_auth_scheme without having set it" do
|
34
|
+
expect {
|
35
|
+
Stitches.configuration.custom_http_auth_scheme
|
36
|
+
}.to raise_error(/you must set a value for custom_http_auth_scheme/i)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
describe "whitelist_regexp" do
|
40
|
+
let(:config) { Stitches::Configuration.new }
|
41
|
+
it "must be a regexp" do
|
42
|
+
expect {
|
43
|
+
config.whitelist_regexp = "foo"
|
44
|
+
}.to raise_error(/whitelist_regexp must be a Regexp/i)
|
45
|
+
end
|
46
|
+
it "may be nil" do
|
47
|
+
expect {
|
48
|
+
config.whitelist_regexp = nil
|
49
|
+
}.not_to raise_error
|
50
|
+
end
|
51
|
+
it "may be a regexp" do
|
52
|
+
expect {
|
53
|
+
config.whitelist_regexp = /foo/
|
54
|
+
}.not_to raise_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "custom_http_auth_scheme" do
|
59
|
+
let(:config) { Stitches::Configuration.new }
|
60
|
+
it "must be a string" do
|
61
|
+
expect {
|
62
|
+
config.custom_http_auth_scheme = 42
|
63
|
+
}.to raise_error(/custom_http_auth_scheme must be a String/i)
|
64
|
+
end
|
65
|
+
it "may not be nil" do
|
66
|
+
expect {
|
67
|
+
config.custom_http_auth_scheme = nil
|
68
|
+
}.to raise_error(/custom_http_auth_scheme may not be blank/i)
|
69
|
+
end
|
70
|
+
it "may not be a blank string" do
|
71
|
+
expect {
|
72
|
+
config.custom_http_auth_scheme = " "
|
73
|
+
}.to raise_error(/custom_http_auth_scheme may not be blank/i)
|
74
|
+
end
|
75
|
+
it "may be a String" do
|
76
|
+
expect {
|
77
|
+
config.custom_http_auth_scheme = "Foobar"
|
78
|
+
}.not_to raise_error
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "env_var_to_hold_api_client_primary_key" do
|
83
|
+
let(:config) { Stitches::Configuration.new }
|
84
|
+
it "must be a string" do
|
85
|
+
expect {
|
86
|
+
config.env_var_to_hold_api_client_primary_key = 42
|
87
|
+
}.to raise_error(/env_var_to_hold_api_client_primary_key must be a String/i)
|
88
|
+
end
|
89
|
+
it "may not be nil" do
|
90
|
+
expect {
|
91
|
+
config.env_var_to_hold_api_client_primary_key = nil
|
92
|
+
}.to raise_error(/env_var_to_hold_api_client_primary_key may not be blank/i)
|
93
|
+
end
|
94
|
+
it "may not be a blank string" do
|
95
|
+
expect {
|
96
|
+
config.env_var_to_hold_api_client_primary_key = " "
|
97
|
+
}.to raise_error(/env_var_to_hold_api_client_primary_key may not be blank/i)
|
98
|
+
end
|
99
|
+
it "may be a String" do
|
100
|
+
expect {
|
101
|
+
config.env_var_to_hold_api_client_primary_key = "Foobar"
|
102
|
+
}.not_to raise_error
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/spec/errors_spec.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
class MyFakeError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class FakePersonHolder
|
7
|
+
include ActiveModel::Validations
|
8
|
+
attr_accessor :name, :person
|
9
|
+
|
10
|
+
validates_presence_of :name
|
11
|
+
|
12
|
+
def valid?
|
13
|
+
# doing this because we can't use validates_associated on a non-AR object, and
|
14
|
+
# our logic doesn't depend on validates_associated, per se
|
15
|
+
super.tap {
|
16
|
+
unless person.valid?
|
17
|
+
errors.add(:person,"is not valid")
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class FakePerson
|
24
|
+
include ActiveModel::Validations
|
25
|
+
|
26
|
+
attr_accessor :first_name, :last_name, :age
|
27
|
+
|
28
|
+
validates_each :first_name, :last_name do |record, attr, value|
|
29
|
+
record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
30
|
+
end
|
31
|
+
|
32
|
+
validates_numericality_of :age
|
33
|
+
validates_presence_of :first_name
|
34
|
+
end
|
35
|
+
|
36
|
+
describe Stitches::Errors do
|
37
|
+
it "can be created from an exception" do
|
38
|
+
exception = MyFakeError.new("OH NOES!")
|
39
|
+
errors = Stitches::Errors.from_exception(exception)
|
40
|
+
|
41
|
+
expect(errors.size).to eq(1)
|
42
|
+
expect(errors.first.code).to eq("my_fake")
|
43
|
+
expect(errors.first.message).to eq("OH NOES!")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "renders useful JSON" do
|
47
|
+
errors = Stitches::Errors.new([
|
48
|
+
Stitches::Error.new(code: "not_found", message: "Was not found, yo"),
|
49
|
+
Stitches::Error.new(code: "and_you_should_feel_bad", message: "And you should feel bad about even asking"),
|
50
|
+
])
|
51
|
+
|
52
|
+
expect(errors.to_json).to eq(
|
53
|
+
[
|
54
|
+
{
|
55
|
+
"code" => "not_found",
|
56
|
+
"message" => "Was not found, yo",
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"code" => "and_you_should_feel_bad",
|
60
|
+
"message" => "And you should feel bad about even asking",
|
61
|
+
}
|
62
|
+
].to_json
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
context "creation from an active record object" do
|
67
|
+
let(:object) { FakePerson.new.tap { |person|
|
68
|
+
person.age = "asdfasdf"
|
69
|
+
person.last_name = "zjohnson"
|
70
|
+
}}
|
71
|
+
it "sets reasonable messages for the fields of the object" do
|
72
|
+
object.valid?
|
73
|
+
errors = Stitches::Errors.from_active_record_object(object)
|
74
|
+
errors_hash = JSON.parse(errors.to_json).sort_by {|_| _["code"] }
|
75
|
+
expect(errors_hash[0]["code"]).to eq("age_invalid")
|
76
|
+
expect(errors_hash[0]["message"]).to eq("Age is not a number")
|
77
|
+
expect(errors_hash[1]["code"]).to eq("first_name_invalid")
|
78
|
+
expect(errors_hash[1]["message"]).to eq("First name can't be blank")
|
79
|
+
expect(errors_hash[2]["code"]).to eq("last_name_invalid")
|
80
|
+
expect(errors_hash[2]["message"]).to eq("Last name starts with z.")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "digs one level deep into the object for associated active-records" do
|
84
|
+
holder = FakePersonHolder.new
|
85
|
+
holder.name = nil
|
86
|
+
holder.person = object
|
87
|
+
|
88
|
+
holder.valid?
|
89
|
+
|
90
|
+
errors = Stitches::Errors.from_active_record_object(holder)
|
91
|
+
errors_hash = JSON.parse(errors.to_json).sort_by {|_| _["code"] }
|
92
|
+
expect(errors_hash[0]["code"]).to eq("name_invalid")
|
93
|
+
expect(errors_hash[0]["message"]).to eq("Name can't be blank")
|
94
|
+
expect(errors_hash[1]["code"]).to eq("person_invalid")
|
95
|
+
expect(errors_hash[1]["message"]).to eq("Age is not a number, First name can't be blank, Last name starts with z.")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
require 'stitches/spec'
|
3
|
+
|
4
|
+
describe "have_api_error" do
|
5
|
+
let(:errors) {
|
6
|
+
[
|
7
|
+
{ code: "foo", message: "bar" },
|
8
|
+
{ code: "baz", message: "quux" }
|
9
|
+
]
|
10
|
+
}
|
11
|
+
let(:response) {
|
12
|
+
double(
|
13
|
+
response_code: response_code,
|
14
|
+
body: { errors: errors }.to_json)
|
15
|
+
}
|
16
|
+
context "missing required arguments from expectation" do
|
17
|
+
let(:response_code) { 422 }
|
18
|
+
it "blows up with a decent message" do
|
19
|
+
expect {
|
20
|
+
expect(response).to have_api_error(message: errors.first[:message])
|
21
|
+
}.to raise_error(/key not found: :code/)
|
22
|
+
expect {
|
23
|
+
expect(response).to have_api_error(code: errors.first[:code])
|
24
|
+
}.to raise_error(/key not found: :message/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context "no expected status specified" do
|
28
|
+
context "status is 422" do
|
29
|
+
let(:response_code) { 422 }
|
30
|
+
context "an error in the expectation exists" do
|
31
|
+
it "indicates there is an error" do
|
32
|
+
expect(response).to have_api_error(errors.first)
|
33
|
+
end
|
34
|
+
it "indicates there is an error for another error in the errors list" do
|
35
|
+
expect(response).to have_api_error(errors.second)
|
36
|
+
end
|
37
|
+
it "indicates there is an error via regexp" do
|
38
|
+
expect(response).to have_api_error(code: errors.second[:code], message: /^.*$/)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
context "no error from the expectation exists" do
|
42
|
+
it "indicates there is no error" do
|
43
|
+
expect(response).not_to have_api_error(code: "blah", message: "crud")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
context "status is 200" do
|
48
|
+
let(:response_code) { 200 }
|
49
|
+
it "indicates there is no error" do
|
50
|
+
expect(response).not_to have_api_error(errors.first)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context "status is e.g. 404" do
|
54
|
+
let(:response_code) { 404 }
|
55
|
+
it "indicates there is no error" do
|
56
|
+
expect(response).not_to have_api_error(errors.first)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context "expected status is specified" do
|
61
|
+
context "status is the expected status" do
|
62
|
+
let(:response_code) { 404 }
|
63
|
+
it "indicates there is an error" do
|
64
|
+
expect(response).to have_api_error(status: 404,
|
65
|
+
code: errors.first[:code],
|
66
|
+
message: errors.first[:message])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
context "status is not the expected status" do
|
70
|
+
let(:response_code) { 422 }
|
71
|
+
it "indicates there is no error" do
|
72
|
+
expect(response).not_to have_api_error(status: 404,
|
73
|
+
code: errors.first[:code],
|
74
|
+
message: errors.first[:bar])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
GEM_ROOT = File.expand_path(File.join(File.dirname(__FILE__),'..'))
|
2
|
+
Dir["#{GEM_ROOT}/spec/support/**/*.rb"].sort.each {|f| require f}
|
3
|
+
|
4
|
+
require 'rails/all'
|
5
|
+
require 'stitches'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.order = "random"
|
9
|
+
end
|
10
|
+
I18n.enforce_available_locales = false # situps
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Stitches::ValidMimeType do
|
4
|
+
let(:app) { double("rack app") }
|
5
|
+
|
6
|
+
before do
|
7
|
+
allow(app).to receive(:call).with(env)
|
8
|
+
end
|
9
|
+
|
10
|
+
subject(:middleware) { described_class.new(app, namespace: "/api") }
|
11
|
+
|
12
|
+
shared_examples "an unacceptable response" do
|
13
|
+
it "returns a 406" do
|
14
|
+
expect(@response.status).to eq(406)
|
15
|
+
end
|
16
|
+
it "stops the call chain preventing anything from happening" do
|
17
|
+
expect(app).not_to have_received(:call)
|
18
|
+
end
|
19
|
+
it "sends a reasonable message" do
|
20
|
+
expect(@response.body.first).to match(/didn't have the right mime type or version number. We only accept application\/json/)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#call" do
|
25
|
+
context "not in namespace" do
|
26
|
+
context "not in whitelist" do
|
27
|
+
let(:env) {
|
28
|
+
{
|
29
|
+
"PATH_INFO" => "/index/home",
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
before do
|
34
|
+
@response = middleware.call(env)
|
35
|
+
end
|
36
|
+
|
37
|
+
it_behaves_like "an unacceptable response"
|
38
|
+
end
|
39
|
+
context "whitelisting" do
|
40
|
+
let(:env) {
|
41
|
+
{
|
42
|
+
"PATH_INFO" => "/index/home",
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
context "whitelist is explicit in middleware usage" do
|
47
|
+
before do
|
48
|
+
@response = middleware.call(env)
|
49
|
+
end
|
50
|
+
|
51
|
+
context "passes the whitelist" do
|
52
|
+
subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
|
53
|
+
let(:env) {
|
54
|
+
{
|
55
|
+
"PATH_INFO" => "/resque/overview"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
it "calls through to the rest of the chain" do
|
59
|
+
expect(app).to have_received(:call).with(env)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "fails the whitelist" do
|
64
|
+
subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
|
65
|
+
let(:env) {
|
66
|
+
{
|
67
|
+
"PATH_INFO" => "//resque/overview" # subtle
|
68
|
+
}
|
69
|
+
}
|
70
|
+
it_behaves_like "an unacceptable response"
|
71
|
+
end
|
72
|
+
context "except: is not given a regexp" do
|
73
|
+
let(:env) {
|
74
|
+
{
|
75
|
+
"PATH_INFO" => "//resque/overview"
|
76
|
+
}
|
77
|
+
}
|
78
|
+
it "blows up" do
|
79
|
+
expect {
|
80
|
+
described_class.new(app, except: "/resque")
|
81
|
+
}.to raise_error(/must be a Regexp/i)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
context "whitelist is implicit from the configuration" do
|
86
|
+
|
87
|
+
before do
|
88
|
+
Stitches.configuration.whitelist_regexp = %r{\A/resque/.*\Z}
|
89
|
+
@response = middleware.call(env)
|
90
|
+
end
|
91
|
+
|
92
|
+
context "passes the whitelist" do
|
93
|
+
subject(:middleware) { described_class.new(app) }
|
94
|
+
let(:env) {
|
95
|
+
{
|
96
|
+
"PATH_INFO" => "/resque/overview"
|
97
|
+
}
|
98
|
+
}
|
99
|
+
it "calls through to the rest of the chain" do
|
100
|
+
expect(app).to have_received(:call).with(env)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "fails the whitelist" do
|
105
|
+
subject(:middleware) { described_class.new(app) }
|
106
|
+
let(:env) {
|
107
|
+
{
|
108
|
+
"PATH_INFO" => "//resque/overview" # subtle
|
109
|
+
}
|
110
|
+
}
|
111
|
+
it_behaves_like "an unacceptable response"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "valid header" do
|
118
|
+
let(:env) {
|
119
|
+
{
|
120
|
+
"PATH_INFO" => "/api/ping",
|
121
|
+
"HTTP_ACCEPT" => "application/json; version=99",
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
before do
|
126
|
+
@response = middleware.call(env)
|
127
|
+
end
|
128
|
+
it "calls through to the rest of the chain" do
|
129
|
+
expect(app).to have_received(:call).with(env)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "unacceptable responses" do
|
134
|
+
before do
|
135
|
+
@response = middleware.call(env)
|
136
|
+
@response.finish
|
137
|
+
end
|
138
|
+
context "no header" do
|
139
|
+
let(:env) {
|
140
|
+
{
|
141
|
+
"PATH_INFO" => "/api/ping",
|
142
|
+
}
|
143
|
+
}
|
144
|
+
it_behaves_like "an unacceptable response"
|
145
|
+
end
|
146
|
+
context "bad mime type" do
|
147
|
+
let(:env) {
|
148
|
+
{
|
149
|
+
"PATH_INFO" => "/api/ping",
|
150
|
+
"HTTP_ACCEPT" => "application/json; version=bleorgh",
|
151
|
+
}
|
152
|
+
}
|
153
|
+
it_behaves_like "an unacceptable response"
|
154
|
+
end
|
155
|
+
context "bad version" do
|
156
|
+
let(:env) {
|
157
|
+
{
|
158
|
+
"PATH_INFO" => "/api/ping",
|
159
|
+
"HTTP_ACCEPT" => "application/xml; version=1",
|
160
|
+
}
|
161
|
+
}
|
162
|
+
it_behaves_like "an unacceptable response"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|