docker-api 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +0 -1
  3. data/README.md +6 -7
  4. data/docker-api.gemspec +3 -4
  5. data/lib/docker.rb +10 -5
  6. data/lib/docker/connection.rb +2 -0
  7. data/lib/docker/container.rb +39 -4
  8. data/lib/docker/error.rb +6 -0
  9. data/lib/docker/event.rb +40 -0
  10. data/lib/docker/image.rb +37 -13
  11. data/lib/docker/util.rb +25 -1
  12. data/lib/docker/version.rb +2 -2
  13. data/spec/docker/container_spec.rb +37 -19
  14. data/spec/docker/event_spec.rb +79 -0
  15. data/spec/docker/image_spec.rb +89 -30
  16. data/spec/docker/util_spec.rb +83 -0
  17. data/spec/docker_spec.rb +47 -2
  18. data/spec/fixtures/{Dockerfile → build_from_dir/Dockerfile} +0 -0
  19. data/spec/fixtures/top/Dockerfile +2 -0
  20. data/spec/support/vcr.rb +1 -4
  21. data/spec/vcr/Docker/_authenticate_/with_valid_credentials/logs_in_and_sets_the_creds.yml +33 -0
  22. data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +7 -7
  23. data/spec/vcr/Docker/_validate_version/when_nothing_is_raised/validate_version_/.yml +6 -6
  24. data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +6 -6
  25. data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +27 -97
  26. data/spec/vcr/Docker_Container/_attach/yields_each_chunk.yml +18 -19
  27. data/spec/vcr/Docker_Container/_changes/returns_the_changes_as_an_array.yml +22 -22
  28. data/spec/vcr/Docker_Container/_commit/creates_a_new_Image_from_the_Container_s_changes.yml +18 -18
  29. data/spec/vcr/Docker_Container/_commit/if_run_is_passed_it_saves_the_command_in_the_image/saves_the_command.yml +178 -0
  30. data/spec/vcr/Docker_Container/_copy/when_the_file_does_not_exist/raises_an_error.yml +54 -24
  31. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_directory/yields_each_chunk_of_the_tarred_directory.yml +27 -60
  32. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_file/yields_each_chunk_of_the_tarred_file.yml +27 -60
  33. data/spec/vcr/Docker_Container/_create/when_the_Container_does_not_yet_exist/when_the_HTTP_request_returns_a_200/sets_the_id.yml +7 -7
  34. data/spec/vcr/Docker_Container/_delete/deletes_the_container.yml +16 -46
  35. data/spec/vcr/Docker_Container/_export/yields_each_chunk.yml +24 -17
  36. data/spec/vcr/Docker_Container/_json/returns_the_description_as_a_Hash.yml +14 -14
  37. data/spec/vcr/Docker_Container/_kill/kills_the_container.yml +36 -49
  38. data/spec/vcr/Docker_Container/_restart/restarts_the_container.yml +43 -43
  39. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_does_not_return_status_code_of_0/raises_an_error.yml +17 -17
  40. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_returns_a_status_code_of_0/creates_a_new_container_to_run_the_specified_command.yml +47 -47
  41. data/spec/vcr/Docker_Container/_start/starts_the_container.yml +25 -25
  42. data/spec/vcr/Docker_Container/_stop/stops_the_container.yml +40 -53
  43. data/spec/vcr/Docker_Container/_top/returns_the_top_commands_as_an_Array.yml +89 -25
  44. data/spec/vcr/Docker_Container/_wait/waits_for_the_command_to_finish.yml +17 -17
  45. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/and_a_command_runs_for_too_long/raises_a_ServerError.yml +12 -12
  46. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/sets_the_read_timeout_to_that_amount_of_time.yml +17 -17
  47. data/spec/vcr/Docker_Image/_all/materializes_each_Image_into_a_Docker_Image.yml +12 -12
  48. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_an_image_and_tags_it.yml +110 -0
  49. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/{builds_an_image.yml → without_query_parameters/builds_an_image.yml} +5 -5
  50. data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +7 -9
  51. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_no_query_parameters/builds_the_image.yml +121 -0
  52. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_the_image_and_tags_it.yml +151 -0
  53. data/spec/vcr/Docker_Image/_create/when_the_Image_does_not_yet_exist_and_the_body_is_a_Hash/sets_the_id.yml +5 -5
  54. data/spec/vcr/Docker_Image/_history/returns_the_history_of_the_Image.yml +10 -10
  55. data/spec/vcr/Docker_Image/_insert/inserts_the_url_s_file_into_a_new_Image.yml +53 -109
  56. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_exist/creates_a_new_Image_that_has_that_file.yml +32 -68
  57. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_not_exist/raises_an_error.yml +5 -5
  58. data/spec/vcr/Docker_Image/_insert_local/when_there_are_multiple_files_passed/creates_a_new_Image_that_has_each_file.yml +40 -68
  59. data/spec/vcr/Docker_Image/_json/returns_additional_information_about_image_image.yml +10 -10
  60. data/spec/vcr/Docker_Image/_push/pushes_the_Image.yml +161 -0
  61. data/spec/vcr/Docker_Image/_remove/removes_the_Image.yml +17 -17
  62. data/spec/vcr/Docker_Image/_run/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +23 -24
  63. data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +23 -24
  64. data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/command_configured_in_image/should_normally_show_result_if_image_has_Cmd_configured.yml +148 -0
  65. data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/no_command_configured_in_image/should_raise_an_error_if_no_command_is_specified.yml +68 -0
  66. data/spec/vcr/Docker_Image/_search/materializes_each_Image_into_a_Docker_Image.yml +13 -11
  67. data/spec/vcr/Docker_Image/_tag/tags_the_image_with_the_repo_name.yml +10 -10
  68. metadata +32 -24
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Docker::Event do
4
+ describe "#to_s" do
5
+ subject { described_class.new(status, id, from, time) }
6
+
7
+ let(:status) { "start" }
8
+ let(:id) { "398c9f77b5d2" }
9
+ let(:from) { "base:latest" }
10
+ let(:time) { 1381956164 }
11
+
12
+ let(:expected_string) {
13
+ "Docker::Event { :status => #{status}, :id => #{id}, "\
14
+ ":from => #{from}, :time => #{time.to_s} }"
15
+ }
16
+
17
+ it "equals the expected string" do
18
+ expect(subject.to_s).to eq(expected_string)
19
+ end
20
+ end
21
+
22
+ describe ".stream" do
23
+ it 'receives three events', :vcr do
24
+ pending "get VCR to record events that break"
25
+ Docker::Event.should_receive(:new_event).exactly(3).times
26
+ .and_call_original
27
+ fork do
28
+ sleep 1
29
+ Docker::Image.create('fromImage' => 'base').run('bash')
30
+ end
31
+ Docker::Event.stream do |event|
32
+ puts "#{event}"
33
+ if event.status == "die"
34
+ break
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ describe ".since" do
41
+ let!(:time) { Time.now.to_i }
42
+
43
+ it 'receives three events', :vcr do
44
+ pending "get VCR to record events that break"
45
+ Docker::Event.should_receive(:new_event).exactly(3).times
46
+ .and_call_original
47
+ fork do
48
+ sleep 1
49
+ Docker::Image.create('fromImage' => 'base').run('bash')
50
+ end
51
+ Docker::Event.since(time) do |event|
52
+ puts "#{event}"
53
+ if event.status == "die"
54
+ break
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ describe ".new_event" do
61
+ subject { Docker::Event.new_event(response_body, nil, nil) }
62
+ let(:status) { "start" }
63
+ let(:id) { "398c9f77b5d2" }
64
+ let(:from) { "base:latest" }
65
+ let(:time) { 1381956164 }
66
+ let(:response_body) {
67
+ "{\"status\":\"#{status}\",\"id\":\"#{id}\""\
68
+ ",\"from\":\"#{from}\",\"time\":#{time}}"
69
+ }
70
+
71
+ it "returns a Docker::Event" do
72
+ expect(subject).to be_kind_of(Docker::Event)
73
+ expect(subject.status).to eq(status)
74
+ expect(subject.id).to eq(id)
75
+ expect(subject.from).to eq(from)
76
+ expect(subject.time).to eq(time)
77
+ end
78
+ end
79
+ end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Docker::Image do
4
4
  describe '#to_s' do
5
- subject { described_class.send(:new, Docker.connection, id) }
5
+ subject { described_class.new(Docker.connection, id, info) }
6
6
 
7
7
  let(:id) { 'bf119e2' }
8
8
  let(:connection) { Docker.connection }
@@ -17,14 +17,6 @@ describe Docker::Image do
17
17
  ":connection => #{connection} }"
18
18
  end
19
19
 
20
- before do
21
- {
22
- :@id => id,
23
- :@connection => connection,
24
- :@info => info
25
- }.each { |k, v| subject.instance_variable_set(k, v) }
26
- end
27
-
28
20
  its(:to_s) { should == expected_string }
29
21
  end
30
22
 
@@ -42,10 +34,10 @@ describe Docker::Image do
42
34
  subject { described_class.build('from base') }
43
35
  let(:new_image) { subject.insert(:path => '/stallman',
44
36
  :url => 'http://stallman.org') }
45
- let(:ls_output) { new_image.run('ls /').attach.split("\n") }
37
+ let(:ls_output) { new_image.run('ls /').attach }
46
38
 
47
39
  it 'inserts the url\'s file into a new Image', :vcr do
48
- ls_output.should include('stallman')
40
+ expect(ls_output.first.first).to include('stallman')
49
41
  end
50
42
  end
51
43
 
@@ -69,9 +61,11 @@ describe Docker::Image do
69
61
  let(:gemfile) { File.read('Gemfile') }
70
62
 
71
63
  it 'creates a new Image that has that file', :vcr do
72
- new_image.run('cat /Gemfile').start.attach { |chunk|
73
- chunk.should == gemfile
64
+ chunk = nil
65
+ new_image.run('cat /Gemfile').attach { |stream, c|
66
+ chunk ||= c
74
67
  }
68
+ expect(chunk).to eq(gemfile)
75
69
  end
76
70
  end
77
71
 
@@ -79,21 +73,38 @@ describe Docker::Image do
79
73
  let(:file) { ['./Gemfile', './Rakefile'] }
80
74
  let(:gemfile) { File.read('Gemfile') }
81
75
  let(:rakefile) { File.read('Rakefile') }
76
+ let(:response) {
77
+ new_image.run('cat /Gemfile /Rakefile').attach
78
+ }
82
79
 
83
80
  it 'creates a new Image that has each file', :vcr do
84
- new_image.run('cat /Gemfile /Rakefile').start.attach do |chunk|
85
- chunk.should == gemfile + rakefile
86
- end
81
+ expect(response).to eq([[gemfile, rakefile],[]])
87
82
  end
88
83
  end
89
84
  end
90
85
 
91
86
  describe '#push' do
92
87
  subject { described_class.create('fromImage' => 'base') }
88
+ let(:credentials) {
89
+ {
90
+ :username => 'test',
91
+ :password => 'test',
92
+ :auth => '',
93
+ :email => 'test@test.com'
94
+ }
95
+ }
96
+ let(:base_image) {
97
+ described_class.create('fromImage' => 'base')
98
+ }
99
+ let(:container) {
100
+ base_image.run('true')
101
+ }
102
+ let(:new_image) {
103
+ container.commit('repo' => 'test/base')
104
+ }
93
105
 
94
106
  it 'pushes the Image', :vcr do
95
- pending 'I don\'t want to push the Image to the Docker Registry'
96
- subject.push
107
+ new_image.push(credentials)
97
108
  end
98
109
  end
99
110
 
@@ -134,7 +145,7 @@ describe Docker::Image do
134
145
  context 'when the argument is a String', :vcr do
135
146
  let(:cmd) { 'ls /lib64/' }
136
147
  it 'splits the String by spaces and creates a new Container' do
137
- output.should == "ld-linux-x86-64.so.2\n"
148
+ expect(output).to eq([["ld-linux-x86-64.so.2\n"],[]])
138
149
  end
139
150
  end
140
151
 
@@ -142,7 +153,26 @@ describe Docker::Image do
142
153
  let(:cmd) { %[which pwd] }
143
154
 
144
155
  it 'creates a new Container', :vcr do
145
- output.should == "/bin/pwd\n"
156
+ expect(output).to eq([["/bin/pwd\n"],[]])
157
+ end
158
+ end
159
+
160
+ context 'when the argument is nil', :vcr do
161
+ let(:cmd) { nil }
162
+ context 'no command configured in image'do
163
+ it 'should raise an error if no command is specified' do
164
+ expect {output}.to raise_error(Docker::Error::ServerError,
165
+ "No command specified.")
166
+ end
167
+ end
168
+
169
+ context "command configured in image" do
170
+ let(:container) {Docker::Container.create('Cmd' => %w[true],
171
+ 'Image' => 'base')}
172
+ subject { container.commit('run' => {"Cmd" => %w[pwd]}) }
173
+ it 'should normally show result if image has Cmd configured' do
174
+ expect(output).to eql [["/\n"],[]]
175
+ end
146
176
  end
147
177
  end
148
178
  end
@@ -229,12 +259,28 @@ describe Docker::Image do
229
259
  end
230
260
 
231
261
  context 'with a valid Dockerfile' do
232
- let(:image) { subject.build("from base\n") }
262
+ context 'without query parameters' do
263
+ let(:image) { subject.build("from base\n") }
233
264
 
234
- it 'builds an image', :vcr do
235
- image.should be_a Docker::Image
236
- image.id.should_not be_nil
237
- image.connection.should be_a Docker::Connection
265
+ it 'builds an image', :vcr do
266
+ expect(image).to be_a Docker::Image
267
+ expect(image.id).to_not be_nil
268
+ expect(image.connection).to be_a Docker::Connection
269
+ end
270
+ end
271
+
272
+ context 'with specifying a repo in the query parameters' do
273
+ let(:image) {
274
+ subject.build("from base\nrun true\n", "t" => "swipely/base")
275
+ }
276
+ let(:images) { subject.all }
277
+
278
+ it 'builds an image and tags it', :vcr do
279
+ expect(image).to be_a Docker::Image
280
+ expect(image.id).to_not be_nil
281
+ expect(image.connection).to be_a Docker::Connection
282
+ expect(images.first.info["Repository"]).to eq("swipely/base")
283
+ end
238
284
  end
239
285
  end
240
286
  end
@@ -243,19 +289,32 @@ describe Docker::Image do
243
289
  subject { described_class }
244
290
 
245
291
  context 'with a valid Dockerfile' do
246
- let(:dir) { File.join(File.dirname(__FILE__), '..', 'fixtures') }
292
+ let(:dir) {
293
+ File.join(File.dirname(__FILE__), '..', 'fixtures', 'build_from_dir')
294
+ }
247
295
  let(:docker_file) { File.new("#{dir}/Dockerfile") }
248
- let(:image) { subject.build_from_dir(dir) }
296
+ let(:image) { subject.build_from_dir(dir, opts) }
297
+ let(:opts) { {} }
249
298
  let(:container) do
250
299
  Docker::Container.create('Image' => image.id,
251
300
  'Cmd' => %w[cat /Dockerfile])
252
301
  end
253
302
  let(:output) { container.tap(&:start)
254
303
  .attach(:stderr => true) }
304
+ let(:images) { subject.all }
255
305
 
256
- it 'builds the image', :vcr do
257
- pending 'webmock / vcr issue'
258
- output.should == docker_file.tap(&:rewind).read
306
+ context 'with no query parameters' do
307
+ it 'builds the image', :vcr do
308
+ expect(output).to eq([[docker_file.read],[]])
309
+ end
310
+ end
311
+
312
+ context 'with specifying a repo in the query parameters' do
313
+ let(:opts) { { "t" => "swipely/base2" } }
314
+ it 'builds the image and tags it', :vcr do
315
+ expect(output).to eq([[docker_file.read],[]])
316
+ expect(images.first.info["Repository"]).to eq("swipely/base2")
317
+ end
259
318
  end
260
319
  end
261
320
  end
@@ -40,4 +40,87 @@ describe Docker::Util do
40
40
  end
41
41
  end
42
42
  end
43
+
44
+ describe '.build_auth_header' do
45
+ subject { described_class }
46
+
47
+ let(:credentials) {
48
+ {
49
+ :username => 'test',
50
+ :password => 'password',
51
+ :email => 'test@example.com',
52
+ :serveraddress => 'https://registry.com/'
53
+ }
54
+ }
55
+ let(:credential_string) { credentials.to_json }
56
+ let(:x_registry_auth) { Base64.encode64(credential_string).gsub(/\n/, '') }
57
+ let(:expected_headers) { { 'X-Registry-Auth' => x_registry_auth } }
58
+
59
+
60
+ context 'given credentials as a Hash' do
61
+ it 'returns an X-Registry-Auth header encoded' do
62
+ expect(subject.build_auth_header(credentials)).to eq(expected_headers)
63
+ end
64
+ end
65
+
66
+ context 'given credentials as a String' do
67
+ it 'returns an X-Registry-Auth header encoded' do
68
+ expect(
69
+ subject.build_auth_header(credential_string)
70
+ ).to eq(expected_headers)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#decipher_messages' do
76
+ context 'given both standard out and standard error' do
77
+ let(:raw_text) {
78
+ "\x01\x00\x00\x00\x00\x00\x00\x01a\x02\x00\x00\x00\x00\x00\x00\x01b"
79
+ }
80
+ let(:expected_messages) { [["a"], ["b"]] }
81
+
82
+ it "returns a single message" do
83
+ expect(
84
+ Docker::Util.decipher_messages(raw_text)
85
+ ).to eq(expected_messages)
86
+ end
87
+ end
88
+
89
+ context 'given a single header' do
90
+ let(:raw_text) { "\x01\x00\x00\x00\x00\x00\x00\x01a" }
91
+ let(:expected_messages) { [["a"], []] }
92
+
93
+ it "returns a single message" do
94
+ expect(
95
+ Docker::Util.decipher_messages(raw_text)
96
+ ).to eq(expected_messages)
97
+ end
98
+ end
99
+
100
+ context 'given two headers' do
101
+ let(:raw_text) {
102
+ "\x01\x00\x00\x00\x00\x00\x00\x01a\x01\x00\x00\x00\x00\x00\x00\x01b"
103
+ }
104
+ let(:expected_messages) { [["a", "b"], []] }
105
+
106
+ it "returns both messages" do
107
+ expect(
108
+ Docker::Util.decipher_messages(raw_text)
109
+ ).to eq(expected_messages)
110
+ end
111
+ end
112
+
113
+ context 'given a header for text longer then 255 characters' do
114
+ let(:raw_text) {
115
+ "\x01\x00\x00\x00\x00\x00\x01\x01" + ("a" * 257)
116
+ }
117
+ let(:expected_messages) { [[("a" * 257)], []] }
118
+
119
+ it "returns both messages" do
120
+ expect(
121
+ Docker::Util.decipher_messages(raw_text)
122
+ ).to eq(expected_messages)
123
+ end
124
+ end
125
+ end
43
126
  end
data/spec/docker_spec.rb CHANGED
@@ -87,8 +87,53 @@ describe Docker do
87
87
  end
88
88
 
89
89
  describe '#authenticate!' do
90
- it 'logs in' do
91
- pending
90
+ subject { described_class }
91
+
92
+ let(:authentication) {
93
+ subject.authenticate!(credentials)
94
+ }
95
+
96
+ after do
97
+ Docker.creds = nil
98
+ end
99
+
100
+ context 'with valid credentials' do
101
+ # Used valid credentials to record VCR and then changed
102
+ # cassette to match these credentials
103
+ let(:credentials) {
104
+ {
105
+ :username => 'test',
106
+ :password => 'account',
107
+ :email => 'test@test.com',
108
+ :serveraddress => 'https://index.docker.io/v1/'
109
+ }
110
+ }
111
+
112
+ it 'logs in and sets the creds', :vcr do
113
+ expect(authentication).to be_true
114
+ expect(Docker.creds).to eq(credentials.to_json)
115
+ end
116
+ end
117
+
118
+ context 'with invalid credentials' do
119
+ # Recorded the VCR with these credentials
120
+ # to purposely fail
121
+ let(:credentials) {
122
+ {
123
+ :username => 'test',
124
+ :password => 'password',
125
+ :email => 'test@example.com',
126
+ :serveraddress => 'https://index.docker.io/v1/'
127
+ }
128
+ }
129
+
130
+ it "raises an error and doesn't set the creds", :vcr do
131
+ pending "VCR won't record when Excon::Expects fail"
132
+ expect {
133
+ authentication
134
+ }.to raise_error(Docker::Error::AuthenticationError)
135
+ expect(Docker.creds).to be_nil
136
+ end
92
137
  end
93
138
  end
94
139
 
@@ -0,0 +1,2 @@
1
+ from base
2
+ run printf '#! /bin/sh\nwhile true\ndo\ntrue\ndone\n' > /while && chmod +x /while
data/spec/support/vcr.rb CHANGED
@@ -1,11 +1,8 @@
1
- require 'webmock'
2
1
  require 'vcr'
3
2
 
4
- WebMock.disable_net_connect!
5
-
6
3
  VCR.configure do |c|
7
4
  c.allow_http_connections_when_no_cassette = false
8
- c.hook_into :webmock
5
+ c.hook_into :excon
9
6
  c.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'vcr')
10
7
  c.configure_rspec_metadata!
11
8
  end
@@ -0,0 +1,33 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: unix:///var/run/docker.sock/v1.6/auth
6
+ body:
7
+ encoding: UTF-8
8
+ string: ! '{"username":"test","password":"account","email":"test@test.com","serveraddress":"https://index.docker.io/v1/"}'
9
+ headers:
10
+ User-Agent:
11
+ - Swipely/Docker-API 1.6.0
12
+ Content-Type:
13
+ - application/json
14
+ response:
15
+ status:
16
+ code: 200
17
+ message:
18
+ headers:
19
+ !binary "Q29udGVudC1UeXBl":
20
+ - !binary |-
21
+ YXBwbGljYXRpb24vanNvbg==
22
+ !binary "Q29udGVudC1MZW5ndGg=":
23
+ - !binary |-
24
+ Mjg=
25
+ !binary "RGF0ZQ==":
26
+ - !binary |-
27
+ RnJpLCAyNSBPY3QgMjAxMyAxNjoyMzo1NSBHTVQ=
28
+ body:
29
+ encoding: US-ASCII
30
+ string: ! '{"Status":"Login Succeeded"}'
31
+ http_version:
32
+ recorded_at: Fri, 25 Oct 2013 16:23:55 GMT
33
+ recorded_with: VCR 2.6.0