messagebus-sdk 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,247 @@
1
+ # Copyright 2013 Message Bus, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+ require 'json'
15
+ require 'net/http'
16
+ require 'messagebus_version'
17
+ require 'messagebus_errors'
18
+
19
+
20
+ module MessagebusSDK
21
+
22
+ class MessagebusBase
23
+ DEFAULT_API_ENDPOINT = 'https://api-v4.messagebus.com'
24
+ DEFAULT = 'DEFAULT'
25
+ HEADER_SESSION_KEY = 'X-MESSAGEBUS-SESSIONKEY'
26
+ SCOPE_ALL = 'all'
27
+ TRUE_VALUE = 'true'
28
+ MAX_TEMPLATE_MESSAGES = 25
29
+
30
+ HTTP_GET = "GET"
31
+ HTTP_POST = "POST"
32
+ HTTP_PUT = "PUT"
33
+ HTTP_DELETE = "DELETE"
34
+
35
+ def initialize(api_key, api_endpoint = DEFAULT_API_ENDPOINT)
36
+ @api_endpoint = api_endpoint
37
+ @api_key = api_key
38
+ init_http_connection(@api_endpoint)
39
+
40
+ @results = base_response_params
41
+ @rest_http_errors = define_rest_http_errors
42
+ end
43
+
44
+ def api_version
45
+ make_api_request("/api/version")
46
+ end
47
+
48
+ def cacert_info(cert_file)
49
+ @http.verify_mode = OpenSSL::SSL::VERIFY_PEER
50
+ if !File.exists?(cert_file)
51
+ raise MessagebusSDK::MissingFileError.new("Unable to read file #{cert_file}")
52
+ end
53
+ @http.ca_file = File.join(cert_file)
54
+ end
55
+
56
+ def format_iso_time(time)
57
+ time.strftime("%Y-%m-%dT%H:%M:%SZ")
58
+ end
59
+
60
+ private
61
+
62
+ def init_http_connection(target_server)
63
+ if (@http and @http.started?)
64
+ @http.finish
65
+ end
66
+ @last_init_time = Time.now.utc
67
+ endpoint_url = URI.parse(target_server)
68
+ @http = Net::HTTP.new(endpoint_url.host, endpoint_url.port)
69
+ @http.use_ssl = true
70
+ @http
71
+ end
72
+
73
+ def common_http_headers
74
+ {'User-Agent' => MessagebusSDK::Info.get_user_agent, 'X-MessageBus-Key' => @api_key}
75
+ end
76
+
77
+ def rest_post_headers
78
+ {"Content-Type" => "application/json; charset=utf-8"}
79
+ end
80
+
81
+ def date_range(start_date, end_date)
82
+ date_range_str=""
83
+ if (start_date!="")
84
+ date_range_str+="startDate=#{start_date}"
85
+ end
86
+ if (end_date!="")
87
+ if (date_range_str!="")
88
+ date_range_str+="&"
89
+ end
90
+ date_range_str+="endDate=#{end_date}"
91
+ end
92
+ date_range_str
93
+ end
94
+
95
+ def set_date(date_string, days_ago)
96
+ if date_string.length == 0
97
+ return date_str_for_time_range(days_ago)
98
+ end
99
+ date_string
100
+ end
101
+
102
+ def date_str_for_time_range(days_ago)
103
+ format_iso_time(Time.now.utc - (days_ago*86400))
104
+ end
105
+
106
+ def well_formed_address?(address)
107
+ !address.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).nil?
108
+ end
109
+
110
+ def make_api_request(path, request_type=HTTP_GET, data='')
111
+ if (@last_init_time < Time.now.utc - 60)
112
+ init_http_connection(@api_endpoint)
113
+ end
114
+
115
+ headers = common_http_headers
116
+ case request_type
117
+ when HTTP_GET
118
+ response = @http.request_get(path, headers)
119
+ when HTTP_PUT
120
+ headers = common_http_headers.merge(rest_post_headers)
121
+ response = @http.request_put(path, data, headers)
122
+ when HTTP_POST
123
+ headers = common_http_headers.merge(rest_post_headers)
124
+ response = @http.request_post(path, data, headers)
125
+ when HTTP_DELETE
126
+ response = @http.delete(path, headers)
127
+ end
128
+ check_response(response)
129
+ end
130
+
131
+ def check_response(response, symbolize_names=true)
132
+ case response
133
+ when Net::HTTPSuccess
134
+ begin
135
+ return JSON.parse(response.body, :symbolize_names => symbolize_names)
136
+ rescue JSON::ParserError => e
137
+ raise MessagebusSDK::RemoteServerError.new("JSON parsing error. Response started with #{response.body.slice(0..9)}")
138
+ end
139
+ when Net::HTTPClientError, Net::HTTPServerError
140
+ if (response.body && response.body.size > 0)
141
+ result = begin
142
+ JSON.parse(response.body, :symbolize_names => symbolize_names)
143
+ rescue JSON::ParserError
144
+ nil
145
+ end
146
+ raise MessagebusSDK::RemoteServerError.new("#{response.code.to_s}:#{rest_http_error_message(response)}")
147
+ else
148
+ raise MessagebusSDK::RemoteServerError.new("#{response.code.to_s}:#{rest_http_error_message(response)}")
149
+ end
150
+ else
151
+ raise "Unexpected HTTP Response: #{response.class.name}"
152
+ end
153
+ raise "Could not determine response"
154
+ end
155
+
156
+ def rest_http_error?(status_code)
157
+ @rest_http_errors.key?(status_code)
158
+ end
159
+
160
+ def rest_http_error_message(response)
161
+ message = "Unknown Error Code"
162
+ message = @rest_http_errors[response.code.to_s] if rest_http_error?(response.code.to_s)
163
+ if (response.body.size > 0)
164
+ values = JSON.parse(response.body)
165
+
166
+ if (values['statusMessage'])
167
+ message += " - " + values['statusMessage']
168
+ end
169
+ end
170
+ message
171
+ end
172
+
173
+ def replace_token_with_key(path, token, key)
174
+ path.gsub(token, key)
175
+ end
176
+
177
+ def replace_channel_key(path, channel_key)
178
+ replace_token_with_key(path, "%CHANNEL_KEY%", channel_key)
179
+ end
180
+
181
+ def replace_channel_and_session_key(path, channel_key, session_key)
182
+ replace_channel_key(replace_token_with_key(path, "%SESSION_KEY%", session_key), channel_key)
183
+ end
184
+
185
+ def feedback_query_args(start_date, end_date, use_send_time, scope)
186
+ query_string_parts = ["useSendTime=#{use_send_time}", "scope=#{scope}"]
187
+ date_range = "#{date_range(start_date, end_date)}"
188
+ query_string_parts << date_range if date_range != ""
189
+ "?" + query_string_parts.join("&")
190
+ end
191
+
192
+ def underscore(camel_cased_word)
193
+ camel_cased_word.to_s.gsub(/::/, '/').
194
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
195
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
196
+ tr("-", "_").
197
+ downcase
198
+ end
199
+
200
+ def snake_case
201
+ return downcase if match(/\A[A-Z]+\z/)
202
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
203
+ gsub(/([a-z])([A-Z])/, '\1_\2').
204
+ downcase
205
+ end
206
+
207
+ def define_rest_http_errors
208
+ {
209
+ "400" => "Invalid Request",
210
+ "401" => "Unauthorized-Missing API Key",
211
+ "403" => "Unauthorized-Invalid API Key",
212
+ "404" => "Incorrect URL",
213
+ "405" => "Method not allowed",
214
+ "406" => "Format not acceptable",
215
+ "408" => "Request Timeout",
216
+ "409" => "Conflict",
217
+ "410" => "Object missing or deleted",
218
+ "413" => "Too many messages in request",
219
+ "415" => "POST JSON data invalid",
220
+ "422" => "Unprocessable Entity",
221
+ "500" => "Internal Server Error",
222
+ "501" => "Not Implemented",
223
+ "503" => "Service Unavailable",
224
+ "507" => "Insufficient Storage"
225
+ }
226
+ end
227
+
228
+ def base_response_params
229
+ {:statusCode => 0,
230
+ :statusMessage => "",
231
+ :statusTime => "1970-01-01T00:00:00.000Z"}
232
+ end
233
+
234
+ def base_message_params
235
+ {:toEmail => '',
236
+ :fromEmail => '',
237
+ :subject => '',
238
+ :toName => '',
239
+ :fromName => '',
240
+ :plaintextBody => '',
241
+ :htmlBody => '',
242
+ :sessionKey => DEFAULT,
243
+ :customHeaders => {} }
244
+ end
245
+
246
+ end
247
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright 2013 Message Bus, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+ module MessagebusSDK
16
+
17
+ class APIParameterError < StandardError
18
+ def initialize(problematic_parameter="")
19
+ super("missing or malformed parameter #{problematic_parameter}")
20
+ end
21
+ end
22
+
23
+ class TemplateError < StandardError
24
+ end
25
+
26
+ class BadAPIKeyError < StandardError
27
+ end
28
+
29
+ class MissingFileError <StandardError
30
+ end
31
+
32
+ class RemoteServerError < StandardError
33
+ attr_reader :result
34
+ def initialize(message, result={})
35
+ super(message)
36
+ @result = result
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright 2012 Mail Bypass, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+ module MessagebusSDK
16
+ VERSION = "4.1.0"
17
+
18
+ class Info
19
+ @@ClientVersion = MessagebusSDK::VERSION
20
+ @@RubyVersion = RUBY_VERSION
21
+ @@UserAgent = "MessagebusAPI:#{@@ClientVersion}-Ruby:#{@@RubyVersion}";
22
+
23
+ def self.get_user_agent
24
+ return @@UserAgent
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,50 @@
1
+ # Copyright 2013 Message Bus, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+ require 'messagebus_base'
16
+
17
+ class MessagebusStatsClient < MessagebusSDK::MessagebusBase
18
+
19
+ def initialize(api_key, api_endpoint = DEFAULT_API_ENDPOINT)
20
+ super(api_key, api_endpoint)
21
+ @rest_endpoints = define_rest_endpoints
22
+ end
23
+
24
+ def stats(start_date = '', end_date = '')
25
+ path = "#{@rest_endpoints[:stats]}?#{date_range(start_date, end_date)}"
26
+ make_api_request(path)
27
+ end
28
+
29
+ def stats_by_channel(channel_key, start_date = '', end_date = '')
30
+ path = "#{replace_channel_key(@rest_endpoints[:stats_channel], channel_key)}?#{date_range(start_date, end_date)}"
31
+ make_api_request(path)
32
+ end
33
+
34
+ def stats_by_session(channel_key, session_key, start_date = '', end_date = '')
35
+ path = "#{replace_channel_and_session_key(@rest_endpoints[:stats_session], channel_key, session_key)}?#{date_range(start_date, end_date)}"
36
+ make_api_request(path)
37
+ end
38
+
39
+ private
40
+
41
+ def define_rest_endpoints
42
+ {
43
+ :stats => "/api/v4/stats/email",
44
+ :stats_channel => "/api/v4/stats/email/channel/%CHANNEL_KEY%",
45
+ :stats_session => "/api/v4/stats/email/channel/%CHANNEL_KEY%/session/%SESSION_KEY%",
46
+ }
47
+ end
48
+
49
+ end
50
+
@@ -0,0 +1,79 @@
1
+ # Copyright 2013 Message Bus, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+ require 'messagebus_base'
16
+
17
+ class MessagebusTemplateClient < MessagebusSDK::MessagebusBase
18
+ DEFAULT_TEMPLATE_ENDPOINT = 'https://templates-v4-jy01-prod.messagebus.com'
19
+
20
+ def initialize(api_key, api_endpoint = DEFAULT_TEMPLATE_ENDPOINT)
21
+ super(api_key, api_endpoint)
22
+ @rest_endpoints = define_rest_endpoints
23
+ end
24
+
25
+ def template_version
26
+ make_api_request(@rest_endpoints[:template_version])
27
+ end
28
+
29
+ def create_template(params)
30
+ path = @rest_endpoints[:templates]
31
+ template_params = base_template_params.merge!(params)
32
+ make_api_request(path, HTTP_POST, template_params.to_json)
33
+ end
34
+
35
+ def get_template(template_key)
36
+ path = replace_token_with_key(@rest_endpoints[:template], "%TEMPLATE_KEY%", template_key)
37
+ make_api_request(path)
38
+ end
39
+
40
+ def send_messages(template_key, params)
41
+ if params.length > MessagebusSDK::MessagebusBase::MAX_TEMPLATE_MESSAGES
42
+ raise MessagebusSDK::TemplateError.new("Max number of template messages per send exceeded #{MessagebusSDK::MessagebusBase::MAX_TEMPLATE_MESSAGES}")
43
+ end
44
+
45
+ path = @rest_endpoints[:templates_send]
46
+ json = {:templateKey => template_key, :messages => params}.to_json
47
+ make_api_request(path, HTTP_POST, json)
48
+ end
49
+
50
+ def templates
51
+ path = "#{@rest_endpoints[:templates]}"
52
+ make_api_request(path)
53
+ end
54
+ end
55
+
56
+ private
57
+ def define_rest_endpoints
58
+ {
59
+ :template_version => "/api/v4/templates/version",
60
+ :template => "/api/v4/template/%TEMPLATE_KEY%",
61
+ :templates => "/api/v4/templates",
62
+ :templates_send => "/api/v4/templates/email/send"
63
+ }
64
+ end
65
+
66
+ def base_template_params
67
+ {:toEmail => '',
68
+ :fromEmail => '',
69
+ :subject => '',
70
+ :toName => '',
71
+ :fromName => '',
72
+ :returnPath => '',
73
+ :plaintextBody => '',
74
+ :htmlBody => '',
75
+ :sessionKey => DEFAULT,
76
+ :options => {},
77
+ :customHeaders => {} }
78
+ end
79
+
@@ -0,0 +1,23 @@
1
+ # Copyright 2012 Mail Bypass, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+ dir = File.dirname(__FILE__)
16
+
17
+ require 'net/https'
18
+ require 'uri'
19
+ require 'cgi'
20
+
21
+ require "#{dir}/messagebus-sdk/messagebus_errors"
22
+ require "#{dir}/messagebus-sdk/messagebus_base"
23
+ require "#{dir}/messagebus-sdk/messagebus_version"
@@ -0,0 +1,71 @@
1
+
2
+ dir = File.dirname(__FILE__)
3
+ require "#{dir}/../spec_helper"
4
+ require "#{dir}/../../lib/messagebus-sdk/api_client"
5
+
6
+ describe MessagebusActionMailerClient do
7
+ attr_reader :client, :api_key
8
+
9
+ before do
10
+ FakeWeb.allow_net_connect = false
11
+ @api_key = "7215ee9c7d9dc229d2921a40e899ec5f"
12
+ @client = MessagebusApiClient.new(@api_key)
13
+ end
14
+
15
+ describe "#deliver" do
16
+ it "works with action mailer" do
17
+ to_email = "hello@example.com"
18
+ session_key = "DEFAULT"
19
+ message = MessageBusActionMailerTest.new_message(to_email, session_key)
20
+
21
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
22
+ message.deliver
23
+
24
+ message_body = JSON.parse(FakeWeb.last_request.body)
25
+ message_params = message_body["messages"][0]
26
+ message_params["toName"].should == ""
27
+ message_params["toEmail"].should == to_email
28
+ message_params["sessionKey"].should == "DEFAULT"
29
+ message_params["customHeaders"].should == {"envelope-sender"=>"bounce@bounce.example.com"}
30
+ end
31
+
32
+ it "works with from with nice name in address" do
33
+ to_email = "Joe Mail <hello_joe@example.com>"
34
+ session_key = "5b39c8b553c821e7cddc6da64b5bd2ee"
35
+ message = MessageBusActionMailerTest.new_message(to_email, session_key)
36
+
37
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
38
+ message.deliver
39
+
40
+ message_body = JSON.parse(FakeWeb.last_request.body)
41
+ message_params = message_body["messages"][0]
42
+ message_params["toName"].should == ""
43
+ message_params["toEmail"].should == "hello_joe@example.com"
44
+ message_params["fromName"].should == "Mail Test"
45
+ message_params["fromEmail"].should == "no-reply@messagebus.com"
46
+ message_params["sessionKey"].should == session_key
47
+ end
48
+
49
+ it "adds bcc and x-* headers to custom_headers" do
50
+ to_email = "hello@example.com"
51
+ session_key = "DEFAULT"
52
+ bcc = "goodbye@example.com"
53
+ x_headers = {"x-header-a" => "header1", "x-tracking" => "1234"}
54
+ message = MessageBusActionMailerTest.new_message(to_email, session_key, bcc, x_headers)
55
+
56
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
57
+ message.deliver
58
+
59
+ message_body = JSON.parse(FakeWeb.last_request.body)
60
+ message_params = message_body["messages"][0]
61
+ message_params["toName"].should == ""
62
+ message_params["toEmail"].should == to_email
63
+ message_params["sessionKey"].should == "DEFAULT"
64
+ message_params["customHeaders"]["envelope-sender"].should == "bounce@bounce.example.com"
65
+ message_params["customHeaders"]["bcc"].should == "goodbye@example.com"
66
+ message_params["customHeaders"]["x-header-a"].should == "header1"
67
+ message_params["customHeaders"]["x-tracking"].should == "1234"
68
+ message_params["customHeaders"]["X-MESSAGEBUS-SESSIONKEY"].should be_nil
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,75 @@
1
+
2
+ dir = File.dirname(__FILE__)
3
+ require "#{dir}/../spec_helper"
4
+ require "#{dir}/../../lib/messagebus-sdk/api_client"
5
+
6
+ describe MessagebusApiClient do
7
+
8
+ class MessagebusApiTest < MessagebusApiClient
9
+ attr_accessor :last_init_time
10
+ end
11
+
12
+ def default_message_params
13
+ {:toEmail => 'apitest1@messagebus.com',
14
+ :toName => 'EmailUser',
15
+ :fromEmail => 'api@messagebus.com',
16
+ :fromName => 'API',
17
+ :subject => 'Unit Test Message',
18
+ :customHeaders => ["sender"=>"apitest1@messagebus.com"],
19
+ :plaintextBody => 'This message is only a test sent by the Ruby Message Bus client library.',
20
+ :htmlBody => "<html><body>This message is only a test sent by the Ruby Message Bus client library.</body></html>",
21
+ :sessionKey => "dab775c6e6aa203324598fefbd1e8baf"
22
+ }
23
+ end
24
+
25
+ attr_reader :client, :api_key
26
+
27
+ before do
28
+ FakeWeb.allow_net_connect = false
29
+ @api_key = "7215ee9c7d9dc229d2921a40e899ec5f"
30
+ @client = MessagebusApiClient.new(@api_key)
31
+ end
32
+
33
+ describe "#send_messages" do
34
+ it "should have user-agent and x-messagebus-key set in request headers" do
35
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
36
+ client.send_messages(default_message_params)
37
+
38
+ FakeWeb.last_request.get_fields("X-MessageBus-Key").should_not be_nil
39
+ FakeWeb.last_request.get_fields("User-Agent").should_not be_nil
40
+ FakeWeb.last_request.get_fields("Content-Type").should_not be_nil
41
+ end
42
+
43
+ it "sends messages" do
44
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
45
+ results = client.send_messages(default_message_params)
46
+ results[:results].size.should == 1
47
+ end
48
+ end
49
+
50
+ describe "http connection" do
51
+ before do
52
+ @http_client = MessagebusApiTest.new(@api_key)
53
+ end
54
+
55
+ it "doesnt reset connection if under a minute old" do
56
+ current_init_time=@http_client.last_init_time
57
+ current_init_time.should be > Time.now.utc-5
58
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
59
+ results = @http_client.send_messages(default_message_params)
60
+ results[:results].size.should == 1
61
+ @http_client.last_init_time.should == current_init_time
62
+ end
63
+
64
+ it "resets connection if over a minute old" do
65
+ @http_client.last_init_time=Time.now.utc-60
66
+ current_init_time=@http_client.last_init_time
67
+ current_init_time.should be < Time.now.utc-59
68
+ FakeWeb.register_uri(:post, "#{API_URL}/message/email/send", :body => json_valid_send)
69
+ results = @http_client.send_messages(default_message_params)
70
+ results[:results].size.should == 1
71
+ @http_client.last_init_time.should be > current_init_time
72
+ end
73
+ end
74
+
75
+ end