Adding batch support
[arvados.git] / spec / google / api_client / batch_spec.rb
1 # Copyright 2012 Google Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain 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,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 require 'spec_helper'
16
17 require 'google/api_client'
18 require 'google/api_client/version'
19
20 describe Google::APIClient::BatchRequest do
21   before do
22     @client = Google::APIClient.new
23   end
24
25   it 'should raise an error if making an empty batch request' do
26     batch = Google::APIClient::BatchRequest.new
27
28     (lambda do
29       @client.execute(batch)
30     end).should raise_error(Google::APIClient::BatchError)
31   end
32
33   describe 'with the discovery API' do
34     before do
35       @client.authorization = nil
36       @discovery = @client.discovered_api('discovery', 'v1')
37     end
38
39     describe 'with two valid requests' do
40       before do
41         @call1 = {
42           :api_method => @discovery.apis.get_rest,
43           :parameters => {
44             'api' => 'adsense',
45             'version' => 'v1'
46           }
47         }
48
49         @call2 = {
50           :api_method => @discovery.apis.get_rest,
51           :parameters => {
52             'api' => 'discovery',
53             'version' => 'v1'
54           }
55         }
56       end
57
58       it 'should execute both when using a global callback' do
59         block_called = 0
60         ids = ['first_call', 'second_call']
61         expected_ids = ids.clone
62         batch = Google::APIClient::BatchRequest.new do |result|
63           block_called += 1
64           result.status.should == 200
65           expected_ids.should include(result.response.call_id)
66           expected_ids.delete(result.response.call_id)
67         end
68
69         batch.add(@call1, ids[0])
70         batch.add(@call2, ids[1])
71
72         @client.execute(batch)
73         block_called.should == 2
74       end
75
76       it 'should execute both when using individual callbacks' do
77         batch = Google::APIClient::BatchRequest.new
78
79         call1_returned, call2_returned = false, false
80         batch.add(@call1) do |result|
81           call1_returned = true
82           result.status.should == 200
83         end
84         batch.add(@call2) do |result|
85           call2_returned = true
86           result.status.should == 200
87         end
88
89         @client.execute(batch)
90         call1_returned.should == true
91         call2_returned.should == true
92       end
93
94       it 'should raise an error if using the same call ID more than once' do
95         batch = Google::APIClient::BatchRequest.new
96
97         (lambda do
98           batch.add(@call1, 'my_id')
99           batch.add(@call2, 'my_id')
100         end).should raise_error(Google::APIClient::BatchError)
101       end
102     end
103
104     describe 'with a valid request and an invalid one' do
105       before do
106         @call1 = {
107           :api_method => @discovery.apis.get_rest,
108           :parameters => {
109             'api' => 'adsense',
110             'version' => 'v1'
111           }
112         }
113
114         @call2 = {
115           :api_method => @discovery.apis.get_rest,
116           :parameters => {
117             'api' => 0,
118             'version' => 1
119           }
120         }
121       end
122
123       it 'should execute both when using a global callback' do
124         block_called = 0
125         ids = ['first_call', 'second_call']
126         expected_ids = ids.clone
127         batch = Google::APIClient::BatchRequest.new do |result|
128           block_called += 1
129           expected_ids.should include(result.response.call_id)
130           expected_ids.delete(result.response.call_id)
131           if result.response.call_id == ids[0]
132             result.status.should == 200
133           else
134             result.status.should >= 400
135             result.status.should < 500
136           end
137         end
138
139         batch.add(@call1, ids[0])
140         batch.add(@call2, ids[1])
141
142         @client.execute(batch)
143         block_called.should == 2
144       end
145
146       it 'should execute both when using individual callbacks' do
147         batch = Google::APIClient::BatchRequest.new
148
149         call1_returned, call2_returned = false, false
150         batch.add(@call1) do |result|
151           call1_returned = true
152           result.status.should == 200
153         end
154         batch.add(@call2) do |result|
155           call2_returned = true
156           result.status.should >= 400
157           result.status.should < 500
158         end
159
160         @client.execute(batch)
161         call1_returned.should == true
162         call2_returned.should == true
163       end
164     end
165   end
166
167   describe 'with the calendar API' do
168     before do
169       @client.authorization = nil
170       @calendar = @client.discovered_api('calendar', 'v3')
171     end
172
173     describe 'with two valid requests' do
174       before do
175         event1 = {
176           'summary' => 'Appointment 1',
177           'location' => 'Somewhere',
178           'start' => {
179             'dateTime' => '2011-01-01T10:00:00.000-07:00'
180           },
181           'end' => {
182             'dateTime' => '2011-01-01T10:25:00.000-07:00'
183           },
184           'attendees' => [
185             {
186               'email' => 'myemail@mydomain.tld'
187             }
188           ]
189         }
190
191         event2 = {
192           'summary' => 'Appointment 2',
193           'location' => 'Somewhere as well',
194           'start' => {
195             'dateTime' => '2011-01-02T10:00:00.000-07:00'
196           },
197           'end' => {
198             'dateTime' => '2011-01-02T10:25:00.000-07:00'
199           },
200           'attendees' => [
201             {
202               'email' => 'myemail@mydomain.tld'
203             }
204           ]
205         }
206
207         @call1 = {
208           :api_method => @calendar.events.insert,
209           :parameters => {'calendarId' => 'myemail@mydomain.tld'},
210           :body => JSON.dump(event1),
211           :headers => {'Content-Type' => 'application/json'}
212         }
213
214         @call2 = {
215           :api_method => @calendar.events.insert,
216           :parameters => {'calendarId' => 'myemail@mydomain.tld'},
217           :body => JSON.dump(event2),
218           :headers => {'Content-Type' => 'application/json'}
219         }
220       end
221
222       it 'should convert to a correct HTTP request' do
223         batch = Google::APIClient::BatchRequest.new { |result| }
224         batch.add(@call1, '1').add(@call2, '2')
225         method, uri, headers, body = batch.to_http_request
226         boundary = Google::APIClient::BatchRequest::BATCH_BOUNDARY
227         method.to_s.downcase.should == 'post'
228         uri.to_s.should == 'https://www.googleapis.com/batch'
229         headers.should == {
230           "Content-Type"=>"multipart/mixed; boundary=#{boundary}"
231         }
232         expected_body = /--#{Regexp.escape(boundary)}\nContent-Type: +application\/http\nContent-ID: +<[\w-]+\+1>\n\nPOST +https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/myemail@mydomain.tld\/events +HTTP\/1.1\nContent-Type: +application\/json\n\n#{Regexp.escape(@call1[:body])}\n\n--#{boundary}\nContent-Type: +application\/http\nContent-ID: +<[\w-]+\+2>\n\nPOST +https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/myemail@mydomain.tld\/events HTTP\/1.1\nContent-Type: +application\/json\n\n#{Regexp.escape(@call2[:body])}\n\n--#{Regexp.escape(boundary)}--/
233         body.gsub("\r", "").should =~ expected_body
234       end
235     end
236   end
237 end