dynamodb 0.0.2 → 1.1.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.
- data/.gitignore +1 -0
- data/Gemfile +2 -1
- data/README.md +41 -11
- data/dynamodb.gemspec +3 -2
- data/lib/dynamodb.rb +18 -17
- data/lib/dynamodb/connection.rb +34 -70
- data/lib/dynamodb/failure_response.rb +41 -0
- data/lib/dynamodb/http_handler.rb +74 -0
- data/lib/dynamodb/request.rb +107 -0
- data/lib/dynamodb/success_response.rb +51 -0
- data/lib/dynamodb/version.rb +3 -0
- data/lib/net/http/connection_pool.rb +226 -0
- data/lib/net/http/connection_pool/connection.rb +189 -0
- data/lib/net/http/connection_pool/session.rb +126 -0
- data/spec/dynamodb/connection_spec.rb +14 -117
- data/spec/dynamodb/failure_response_spec.rb +27 -0
- data/spec/dynamodb/http_handler_spec.rb +71 -0
- data/spec/dynamodb/request_spec.rb +31 -0
- data/spec/dynamodb/success_response_spec.rb +93 -0
- data/spec/dynamodb_spec.rb +24 -0
- metadata +18 -28
- data/lib/dynamodb/credentials.rb +0 -30
- data/lib/dynamodb/response.rb +0 -33
- data/lib/dynamodb/security_token_service.rb +0 -110
- data/lib/dynamodb/typhoeus/request.rb +0 -27
- data/spec/dynamodb/credentials_spec.rb +0 -22
- data/spec/dynamodb/response_spec.rb +0 -87
- data/spec/dynamodb/security_token_service_spec.rb +0 -97
@@ -0,0 +1,126 @@
|
|
1
|
+
# Copyright 2011-2012 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
# http://aws.amazon.com/apache2.0/
|
8
|
+
#
|
9
|
+
# or in the "license" file accompanying this file. This file is
|
10
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
11
|
+
# ANY KIND, either express or implied. See the License for the specific
|
12
|
+
# language governing permissions and limitations under the License.
|
13
|
+
|
14
|
+
require 'net/http'
|
15
|
+
require 'net/https'
|
16
|
+
require 'openssl'
|
17
|
+
|
18
|
+
class Net::HTTP::ConnectionPool
|
19
|
+
|
20
|
+
# Used by Net::HTTP::ConnectionPool to wrap Net::HTTP::Session objects.
|
21
|
+
# Users should never need to interact with these session wrappers.
|
22
|
+
# @private
|
23
|
+
class Session
|
24
|
+
|
25
|
+
# @param [Net::HTTPSession] http_session
|
26
|
+
# @param [String] key
|
27
|
+
def initialize http_session, key
|
28
|
+
@http_session = http_session
|
29
|
+
@key = key
|
30
|
+
@created_at = Time.now
|
31
|
+
@last_used_at = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Net::HTTPSession]
|
35
|
+
attr_reader :http_session
|
36
|
+
|
37
|
+
# @return [String]
|
38
|
+
attr_reader :key
|
39
|
+
|
40
|
+
# @return [Time]
|
41
|
+
attr_reader :created_at
|
42
|
+
|
43
|
+
# @return [Time]
|
44
|
+
attr_reader :last_used_at
|
45
|
+
|
46
|
+
# @param [Integer] timeout Number of seconds before Net::HTTP should
|
47
|
+
# timeout while waiting to read a response.
|
48
|
+
def read_timeout= timeout
|
49
|
+
http_session.read_timeout = timeout
|
50
|
+
end
|
51
|
+
|
52
|
+
# Makes a HTTP request. See Net::HTTPSession#request documentation
|
53
|
+
# from the Ruby standard library for information about argments.
|
54
|
+
#
|
55
|
+
# connection.request(Net::HTTP::Get.new('/')) do |response|
|
56
|
+
# # Parse the response (status, headers and body) here.
|
57
|
+
# # You should be done with the response by the end of the block.
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# @yield [response]
|
61
|
+
# @yieldparam [Net::HTTPResponse] response
|
62
|
+
# @return [nil]
|
63
|
+
def request *args, &block
|
64
|
+
http_session.request(*args, &block)
|
65
|
+
@last_used_at = Time.now
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Attempts to cleanly close the HTTP session.
|
70
|
+
# @return [nil]
|
71
|
+
def finish
|
72
|
+
begin
|
73
|
+
http_session.finish if http_session.started?
|
74
|
+
rescue IOError
|
75
|
+
end
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
|
81
|
+
# Starts a new HTTP session and returns it wrapped in a {Session} object.
|
82
|
+
# @param [Connection] connection
|
83
|
+
# @param [Hash] options
|
84
|
+
# @option options [Integer] :open_timeout (15) The number of seconds to
|
85
|
+
# wait while trying to open the HTTP session before timeing out.
|
86
|
+
# @option options [Logger] :debug_logger HTTP wire traces are logged
|
87
|
+
# here when specified.
|
88
|
+
# @return [Session]
|
89
|
+
def start connection, options = {}
|
90
|
+
|
91
|
+
http_args = []
|
92
|
+
http_args << connection.host
|
93
|
+
http_args << connection.port
|
94
|
+
if connection.proxy?
|
95
|
+
http_args << connection.proxy_address
|
96
|
+
http_args << connection.proxy_port
|
97
|
+
http_args << connection.proxy_user
|
98
|
+
http_args << connection.proxy_password
|
99
|
+
end
|
100
|
+
|
101
|
+
http = Net::HTTP.new(*http_args)
|
102
|
+
http.set_debug_output(options[:debug_logger]) if options[:debug_logger]
|
103
|
+
http.open_timeout = options[:open_timeout] || 15
|
104
|
+
|
105
|
+
if connection.ssl?
|
106
|
+
http.use_ssl = true
|
107
|
+
if connection.ssl_verify_peer?
|
108
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
109
|
+
http.ca_file = connection.ssl_ca_file if connection.ssl_ca_file
|
110
|
+
http.ca_path = connection.ssl_ca_path if connection.ssl_ca_path
|
111
|
+
else
|
112
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
113
|
+
end
|
114
|
+
else
|
115
|
+
http.use_ssl = false
|
116
|
+
end
|
117
|
+
|
118
|
+
http.start
|
119
|
+
|
120
|
+
Session.new(http, connection.key)
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -1,131 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'benchmark'
|
3
2
|
|
4
3
|
describe DynamoDB::Connection do
|
5
|
-
let(:token_service) {
|
6
|
-
stub(:credentials =>
|
7
|
-
DynamoDB::Credentials.new(
|
8
|
-
"access_key_id",
|
9
|
-
"secret_access_key",
|
10
|
-
"session_token"
|
11
|
-
)
|
12
|
-
)
|
13
|
-
}
|
14
|
-
|
15
|
-
describe "#initialize" do
|
16
|
-
it "can be initialized with a token service" do
|
17
|
-
DynamoDB::Connection.new(:token_service => token_service)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "can be initialized with an access key" do
|
21
|
-
DynamoDB::Connection.new(
|
22
|
-
:access_key_id => "id",
|
23
|
-
:secret_access_key => "secret"
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
context "no token service was provided" do
|
28
|
-
it "requires an access_key_id and secret_access_key" do
|
29
|
-
lambda {
|
30
|
-
DynamoDB::Connection.new
|
31
|
-
}.should raise_error(ArgumentError)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
4
|
describe "#post" do
|
37
|
-
let(:connection) { DynamoDB::Connection.new(:
|
38
|
-
|
39
|
-
before do
|
40
|
-
Time.stub(:now => Time.at(1332635893)) # Sat Mar 24 20:38:13 -0400 2012
|
41
|
-
|
42
|
-
@url = "https://dynamodb.us-east-1.amazonaws.com/"
|
43
|
-
@headers = {
|
44
|
-
'Content-Type' => 'application/x-amz-json-1.0',
|
45
|
-
'Host' => 'dynamodb.us-east-1.amazonaws.com',
|
46
|
-
'X-Amz-Date' => 'Sun, 25 Mar 2012 00:38:13 GMT',
|
47
|
-
'X-Amz-Security-Token' => 'session_token',
|
48
|
-
'X-Amzn-Authorization' => 'AWS3 AWSAccessKeyId=access_key_id,Algorithm=HmacSHA256,Signature=2xa6v0WW+980q8Hgt+ym3/7C0D1DlkueGMugi1NWE+o='
|
49
|
-
}
|
50
|
-
end
|
5
|
+
let(:connection) { DynamoDB::Connection.new(:access_key_id => "id", :secret_access_key => "secret") }
|
51
6
|
|
52
7
|
it "signs and posts a request" do
|
53
|
-
|
54
|
-
|
55
|
-
with(
|
56
|
-
:body => "{}",
|
57
|
-
:headers => @headers
|
58
|
-
).
|
59
|
-
to_return(
|
60
|
-
:status => 200,
|
61
|
-
:body => '{"TableNames":["example"]}',
|
62
|
-
:headers => {}
|
63
|
-
)
|
64
|
-
|
8
|
+
stub_request(:post, "https://dynamodb.us-east-1.amazonaws.com/").
|
9
|
+
to_return(status: 200, body: MultiJson.encode({"TableNames" => ["example"]}))
|
65
10
|
result = connection.post :ListTables
|
66
|
-
result.should == {"TableNames" => ["example"]}
|
67
|
-
end
|
68
|
-
|
69
|
-
it "type casts response when Query" do
|
70
|
-
stub_request(:post, @url).
|
71
|
-
to_return(
|
72
|
-
:status => 200,
|
73
|
-
:body => "{}",
|
74
|
-
:headers => {}
|
75
|
-
)
|
76
|
-
|
77
|
-
response = connection.post :Query, :TableName => "people", :HashKeyId => {:N => "1"}
|
78
|
-
response.should be_a_kind_of(DynamoDB::Response)
|
11
|
+
result.data.should == {"TableNames" => ["example"]}
|
79
12
|
end
|
80
13
|
|
81
|
-
it "
|
82
|
-
stub_request(:post,
|
83
|
-
to_return(
|
84
|
-
|
85
|
-
|
86
|
-
:headers => {}
|
87
|
-
)
|
88
|
-
|
89
|
-
response = connection.post :GetItem, :TableName => "people", :Key => {:HashKeyElement => {:N => "1"}, :RangeKeyElement => {:N => 2}}
|
90
|
-
response.should be_a_kind_of(DynamoDB::Response)
|
91
|
-
end
|
92
|
-
|
93
|
-
context "when a failure occurs" do
|
94
|
-
it "raises an error with the response attached" do
|
95
|
-
stub_request(:post, @url).to_return(:status => 500, :body => "Failed for some reason.")
|
96
|
-
error = nil
|
97
|
-
begin
|
98
|
-
connection.post :Query, :TableName => "people", :HashKeyId => {:N => "1"}
|
99
|
-
rescue => e
|
100
|
-
error = e
|
101
|
-
end
|
102
|
-
error.should be_an_instance_of(DynamoDB::ServerError)
|
103
|
-
error.response.code.should == 500
|
104
|
-
error.message.should == "500: Failed for some reason."
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context "when the connection fails" do
|
109
|
-
it "raises a server error" do
|
110
|
-
stub_request(:post, @url).to_return(:status => 0, :body => "")
|
111
|
-
error = nil
|
112
|
-
begin
|
113
|
-
connection.post :Query, :TableName => "people", :HashKeyId => {:N => "1"}
|
114
|
-
rescue => e
|
115
|
-
error = e
|
116
|
-
end
|
117
|
-
error.should be_an_instance_of(DynamoDB::ServerError)
|
118
|
-
error.response.code.should == 0
|
119
|
-
end
|
14
|
+
it "creates a SuccessResponse when 200" do
|
15
|
+
stub_request(:post, "https://dynamodb.us-east-1.amazonaws.com/").
|
16
|
+
to_return(status: 200, body: "")
|
17
|
+
result = connection.post :ListTables
|
18
|
+
result.should be_a_kind_of(DynamoDB::SuccessResponse)
|
120
19
|
end
|
121
20
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
}.to raise_error(DynamoDB::TimeoutError)
|
128
|
-
end
|
21
|
+
it "creates a FailureResponse when 400" do
|
22
|
+
stub_request(:post, "https://dynamodb.us-east-1.amazonaws.com/").
|
23
|
+
to_return(status: 400, body: "")
|
24
|
+
result = connection.post :ListTables
|
25
|
+
result.should be_a_kind_of(DynamoDB::FailureResponse)
|
129
26
|
end
|
130
27
|
end
|
131
28
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DynamoDB::FailureResponse do
|
4
|
+
describe "#error" do
|
5
|
+
it "returns a ClientError if the HTTP response code is between 400 and 499" do
|
6
|
+
http_response = stub("Response", code: "401", message: "Not authorized", body: "Error details")
|
7
|
+
response = DynamoDB::FailureResponse.new(http_response)
|
8
|
+
response.error.should be_an_instance_of(DynamoDB::ClientError)
|
9
|
+
response.error.message.should == "401: Not authorized"
|
10
|
+
response.body.should == "Error details"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns a ServerError if the HTTP response code is between 500 and 599" do
|
14
|
+
http_response = stub("Response", code: "500", message: "Internal server error", body: "")
|
15
|
+
response = DynamoDB::FailureResponse.new(http_response)
|
16
|
+
response.error.should be_an_instance_of(DynamoDB::ServerError)
|
17
|
+
response.error.message.should == "500: Internal server error"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns a ServerError otherwise" do
|
21
|
+
http_response = stub("Response", code: "0", message: "")
|
22
|
+
response = DynamoDB::FailureResponse.new(http_response)
|
23
|
+
response.error.should be_an_instance_of(DynamoDB::ServerError)
|
24
|
+
response.error.message.should == "0: "
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DynamoDB::HttpHandler do
|
4
|
+
describe "#handle" do
|
5
|
+
let(:http_handler) { DynamoDB::HttpHandler.new }
|
6
|
+
let(:request) {
|
7
|
+
stub(DynamoDB::Request,
|
8
|
+
uri: URI("https://dynamo.local/"),
|
9
|
+
headers: {},
|
10
|
+
body: "{}"
|
11
|
+
)
|
12
|
+
}
|
13
|
+
|
14
|
+
it "performs an HTTP request given a DynamoDB::Request" do
|
15
|
+
http_request = stub_request(:post, "https://dynamo.local/").to_return(status: 200)
|
16
|
+
http_handler.handle(request)
|
17
|
+
http_request.should have_been_requested
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns a DynamoDB::SuccessResponse for successes" do
|
21
|
+
stub_request(:post, "https://dynamo.local/").to_return(status: 200)
|
22
|
+
|
23
|
+
response = http_handler.handle(request)
|
24
|
+
response.should be_an_instance_of(DynamoDB::SuccessResponse)
|
25
|
+
response.should be_success
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns a DynamoDB::Response for failures" do
|
29
|
+
stub_request(:post, "https://dynamo.local/").to_return(status: 500, body: "Server errors")
|
30
|
+
|
31
|
+
response = http_handler.handle(request)
|
32
|
+
response.should be_an_instance_of(DynamoDB::FailureResponse)
|
33
|
+
response.should_not be_success
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns a DynamoDB::Response for network errors" do
|
37
|
+
error = Errno::ECONNRESET.new
|
38
|
+
stub_request(:post, "https://dynamo.local/").to_raise(error)
|
39
|
+
|
40
|
+
response = http_handler.handle(request)
|
41
|
+
response.should be_an_instance_of(DynamoDB::FailureResponse)
|
42
|
+
response.should_not be_success
|
43
|
+
response.error.should == error
|
44
|
+
response.body.should be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "respects a custom timeout option (set on initialize)" do
|
48
|
+
stub_request(:post, "https://dynamo.local/").to_return(status: 200)
|
49
|
+
connection = Net::HTTP::ConnectionPool::Connection.any_instance
|
50
|
+
connection.should_receive(:read_timeout=).with(5)
|
51
|
+
http_handler.handle(request)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#build_http_request" do
|
56
|
+
it "converts a DynamoDB::Request into a Net::HTTP::Post" do
|
57
|
+
request = stub(DynamoDB::Request,
|
58
|
+
uri: URI("https://dynamo.local/"),
|
59
|
+
headers: {"content-type" => "application/json"},
|
60
|
+
body: "POST body"
|
61
|
+
)
|
62
|
+
|
63
|
+
http_handler = DynamoDB::HttpHandler.new
|
64
|
+
http_request = http_handler.build_http_request(request)
|
65
|
+
http_request.should be_an_instance_of(Net::HTTP::Post)
|
66
|
+
http_request.path.should == "https://dynamo.local/"
|
67
|
+
http_request["content-type"].should == "application/json"
|
68
|
+
http_request.body.should == "POST body"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DynamoDB::Request do
|
4
|
+
let(:uri) { URI("https://dynamodb.us-east-1.amazonaws.com/") }
|
5
|
+
let(:credentials) { DynamoDB::Credentials.new("access_key_id", "secret_access_key") }
|
6
|
+
let(:data) { {} }
|
7
|
+
let(:request) {
|
8
|
+
DynamoDB::Request.new(
|
9
|
+
uri: uri,
|
10
|
+
api_version: "DynamoDB_20111205",
|
11
|
+
credentials: credentials,
|
12
|
+
data: data,
|
13
|
+
operation: "ListTables",
|
14
|
+
)
|
15
|
+
}
|
16
|
+
|
17
|
+
it "signs the request" do
|
18
|
+
Time.stub(now: Time.parse("20130508T201304Z"))
|
19
|
+
|
20
|
+
request.headers.should == {
|
21
|
+
"content-type"=>"application/x-amz-json-1.0",
|
22
|
+
"x-amz-target"=>"DynamoDB_20111205.ListTables",
|
23
|
+
"content-length"=>2,
|
24
|
+
"user-agent"=>"groupme/dynamodb",
|
25
|
+
"host"=>"dynamodb.us-east-1.amazonaws.com",
|
26
|
+
"x-amz-date"=>"20130508T201304Z",
|
27
|
+
"x-amz-content-sha256"=>"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
|
28
|
+
"authorization"=>"AWS4-HMAC-SHA256 Credential=access_key_id/20130508/us-east-1/dynamodb/aws4_request, SignedHeaders=content-length;content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target, Signature=52fab5c720b35ce247f8388c5c8f66b300074ae88b666985ee26ca70d923be1d"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DynamoDB::SuccessResponse do
|
4
|
+
describe "#hash_key_element" do
|
5
|
+
it "returns the typecast value of HashKeyElement" do
|
6
|
+
body = {
|
7
|
+
"LastEvaluatedKey" => {
|
8
|
+
"HashKeyElement" => {"N" => "1"},
|
9
|
+
"RangeKeyElement" => {"N" => "1501"}
|
10
|
+
}
|
11
|
+
}
|
12
|
+
http_response = stub(Net::HTTPResponse, body: MultiJson.dump(body))
|
13
|
+
response = DynamoDB::SuccessResponse.new(http_response)
|
14
|
+
response.hash_key_element.should == 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#range_key_element" do
|
19
|
+
it "returns the typecast value of RangeKeyElement" do
|
20
|
+
body = {
|
21
|
+
"LastEvaluatedKey" => {
|
22
|
+
"HashKeyElement" => {"N" => "1"},
|
23
|
+
"RangeKeyElement" => {"N" => "1501"}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
http_response = stub(Net::HTTPResponse, body: MultiJson.dump(body))
|
27
|
+
response = DynamoDB::SuccessResponse.new(http_response)
|
28
|
+
response.range_key_element.should == 1501
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#items" do
|
33
|
+
it "returns type-casted entries from the 'Items' key" do
|
34
|
+
body = {
|
35
|
+
"Items" => [
|
36
|
+
{
|
37
|
+
"name" => {"S" => "John Smith"},
|
38
|
+
"created_at" => {"N" => "1321564309.99428"},
|
39
|
+
"disabled" => {"N" => "0"},
|
40
|
+
"group_id" => {"N" => "1"},
|
41
|
+
"person_id" => {"N" => "1500"}
|
42
|
+
},
|
43
|
+
{
|
44
|
+
"name" => {"S" => "Jane Smith"},
|
45
|
+
"created_at" => {"N" => "1321564309.99428"},
|
46
|
+
"disabled" => {"N" => "1"},
|
47
|
+
"group_id" => {"N" => "1"},
|
48
|
+
"person_id" => {"N" => "1501"}
|
49
|
+
}
|
50
|
+
],
|
51
|
+
"Count" => 1,
|
52
|
+
"ConsumedCapacityUnits" => 0.5
|
53
|
+
}
|
54
|
+
http_response = stub(Net::HTTPResponse, body: MultiJson.dump(body))
|
55
|
+
|
56
|
+
response = DynamoDB::SuccessResponse.new(http_response)
|
57
|
+
response.items[0]["name"].should == "John Smith"
|
58
|
+
response.items[0]["created_at"].should == 1321564309.99428
|
59
|
+
response.items[0]["disabled"].should == 0
|
60
|
+
response.items[0]["group_id"].should == 1
|
61
|
+
response.items[0]["person_id"].should == 1500
|
62
|
+
|
63
|
+
response.items[1]["name"].should == "Jane Smith"
|
64
|
+
response.items[1]["created_at"].should == 1321564309.99428
|
65
|
+
response.items[1]["disabled"].should == 1
|
66
|
+
response.items[1]["group_id"].should == 1
|
67
|
+
response.items[1]["person_id"].should == 1501
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#item" do
|
72
|
+
it "returns the type-casted 'Item' key" do
|
73
|
+
body = {
|
74
|
+
"Item"=> {
|
75
|
+
"name" => {"S" => "John Smith"},
|
76
|
+
"created_at" => {"N" => "1321564309.99428"},
|
77
|
+
"disabled" => {"N" => "0"},
|
78
|
+
"group_id" => {"N" => "1"},
|
79
|
+
"person_id" => {"N" => "1500"}
|
80
|
+
},
|
81
|
+
"ConsumedCapacityUnits" => 0.5
|
82
|
+
}
|
83
|
+
http_response = stub(Net::HTTPResponse, body: MultiJson.dump(body))
|
84
|
+
|
85
|
+
response = DynamoDB::SuccessResponse.new(http_response)
|
86
|
+
response.item["name"].should == "John Smith"
|
87
|
+
response.item["created_at"].should == 1321564309.99428
|
88
|
+
response.item["disabled"].should == 0
|
89
|
+
response.item["group_id"].should == 1
|
90
|
+
response.item["person_id"].should == 1500
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|