yt 0.5.12 → 0.5.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7a1e9d6fa998dd66d1929e0a2c39fbc0d18af93
4
- data.tar.gz: 1be8fb1e1e1b38d3d2b5f8bfc074511f2dd44b4f
3
+ metadata.gz: bc79b5682be98448f4c2ad0e47e025ece396f2ca
4
+ data.tar.gz: 3b3ba9a7646c1fe350c10bf1cc01ffc9e3c01062
5
5
  SHA512:
6
- metadata.gz: cd51e6439cd718fd612ac6433d003da818155f79b4d824c146161a7398f5c52ffa7c2c47807e66b29d08251c758fc10663ed742086b4793c5471f852e70bf109
7
- data.tar.gz: c0ebf331e22a6b59fa2f56293a01e0a85e1c729636916e0eeccf1856c9cf4715ba91f0c8a98d2325a5f103bed7331adbbc671c970f88d2cccb904b175f73b0eb
6
+ metadata.gz: e8be6da305362d7f2578157ba5cdd0d6c717bbbd8f5a677ac898af79332fc5bb098b0f777006fc7d002da696346403910d724c673e308d897b1c700fa83e295e
7
+ data.tar.gz: 90842585d61ad708d4dba3fefac8b7bc2f51ac8eeae58ca3acdd5d989bf4eae495ba9a6b984b758f4e7bc5f2b20a5d8f14604c6e821ecb935745af67fb5363c8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yt (0.5.12)
4
+ yt (0.5.13)
5
5
  activesupport
6
6
 
7
7
  GEM
data/HISTORY.md CHANGED
@@ -19,6 +19,7 @@ v0.5 - 2014/05/16
19
19
  * New ContentOwner subclass of Account with access to partnered channels
20
20
  * Automatically refresh the access token when it expires or becomes invalid
21
21
  * Retry once YouTube earning queries that return error 503
22
+ * Wait 3 seconds and retry *every* request that returns 500, 503 or 400 with "Invalid query"
22
23
 
23
24
  v0.4 - 2014/05/09
24
25
  --------------------
data/README.md CHANGED
@@ -365,7 +365,7 @@ To install on your system, run
365
365
 
366
366
  To use inside a bundled Ruby project, add this line to the Gemfile:
367
367
 
368
- gem 'yt', '~> 0.5.12'
368
+ gem 'yt', '~> 0.5.13'
369
369
 
370
370
  Since the gem follows [Semantic Versioning](http://semver.org),
371
371
  indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
@@ -4,17 +4,9 @@ module Yt
4
4
  module Collections
5
5
  class Earnings < Base
6
6
 
7
- def within(days_range, try_again = true)
7
+ def within(days_range)
8
8
  @days_range = days_range
9
9
  Hash[*flat_map{|daily_earning| daily_earning}]
10
- # NOTE: Once in a while, YouTube responds with 400 Error and the message
11
- # "Invalid query. Query did not conform to the expectations."; in this
12
- # case running the same query after one second fixes the issue. This is
13
- # not documented by YouTube and hardly testable, but trying again the
14
- # same query is a workaround that works and can hardly cause any damage.
15
- # Similarly, once in while YouTube responds with a random 503 error.
16
- rescue Yt::Error => e
17
- try_again && rescue?(e) ? sleep(3) && within(days_range, false) : raise
18
10
  end
19
11
 
20
12
  private
@@ -41,18 +33,6 @@ module Yt
41
33
  def items_key
42
34
  'rows'
43
35
  end
44
-
45
- def rescue?(error)
46
- bad_request?(error) || backend_error?(error)
47
- end
48
-
49
- def bad_request?(error)
50
- 'badRequest'.in?(error.reasons) && error.message =~ /did not conform/
51
- end
52
-
53
- def backend_error?(error)
54
- 'backendError'.in?(error.reasons)
55
- end
56
36
  end
57
37
  end
58
38
  end
@@ -28,25 +28,13 @@ module Yt
28
28
  def run
29
29
  if response.is_a? @expected_response
30
30
  response.tap{|response| response.body = parse_format response.body}
31
- elsif run_again_with_refreshed_authentication?
32
- run
33
31
  else
34
- raise error_for(response), request_error_message
32
+ run_again? ? run : raise(error_for(response), request_error_message)
35
33
  end
36
34
  end
37
35
 
38
36
  private
39
37
 
40
- # If a request authorized with an access token returns 401, then the
41
- # access token might have expired. If a refresh token is also present,
42
- # try to run the request one more time with a refreshed access token.
43
- def run_again_with_refreshed_authentication?
44
- if response.is_a? Net::HTTPUnauthorized
45
- @response = @http_request = @uri = nil
46
- @auth.refresh
47
- end if @auth.respond_to? :refresh
48
- end
49
-
50
38
  def response
51
39
  @response ||= Net::HTTP.start(*net_http_options) do |http|
52
40
  http.request http_request
@@ -113,6 +101,45 @@ module Yt
113
101
  end if body
114
102
  end
115
103
 
104
+ # There are two cases to run a request again: YouTube responds with a
105
+ # random error that can be fixed by waiting for some seconds and running
106
+ # the exact same query, or the access token needs to be refreshed.
107
+ def run_again?
108
+ run_again_with_refreshed_authentication? || run_again_after_a_while?
109
+ end
110
+
111
+ # Once in a while, YouTube responds with 500, or 503, or 400 Error and
112
+ # the text "Invalid query. Query did not conform to the expectations.".
113
+ # In all these cases, running the same query after some seconds fixes
114
+ # the issue. This it not documented by YouTube and hardly testable, but
115
+ # trying again is a workaround that works and hardly causes any damage.
116
+ def run_again_after_a_while?(max_retries = 1)
117
+ @retries_so_far ||= -1
118
+ @retries_so_far += 1
119
+ if (@retries_so_far < max_retries) && worth_another_try?
120
+ @response = @http_request = @uri = nil
121
+ sleep 3
122
+ end
123
+ end
124
+
125
+ def worth_another_try?
126
+ case response
127
+ when Net::HTTPServerError then true
128
+ when Net::HTTPBadRequest then response.body =~ /did not conform/
129
+ else false
130
+ end
131
+ end
132
+
133
+ # If a request authorized with an access token returns 401, then the
134
+ # access token might have expired. If a refresh token is also present,
135
+ # try to run the request one more time with a refreshed access token.
136
+ def run_again_with_refreshed_authentication?
137
+ if response.is_a? Net::HTTPUnauthorized
138
+ @response = @http_request = @uri = nil
139
+ @auth.refresh
140
+ end if @auth.respond_to? :refresh
141
+ end
142
+
116
143
  def error_for(response)
117
144
  case response
118
145
  when Net::HTTPServerError then Errors::ServerError
data/lib/yt/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yt
2
- VERSION = '0.5.12'
2
+ VERSION = '0.5.13'
3
3
  end
@@ -7,7 +7,8 @@ describe Yt::Associations::PartneredChannels, :partner do
7
7
  context 'given a content owner with partnered channels' do
8
8
  let(:content_owner) { $content_owner }
9
9
 
10
- it { expect(partnered_channels.count).to be > 0 }
10
+ # NOTE: Uncomment once size does not runs through *all* the pages
11
+ # it { expect(partnered_channels.size).to be > 0 }
11
12
  it { expect(partnered_channels.first).to be_a Yt::Channel }
12
13
  end
13
14
  end
@@ -4,10 +4,8 @@ require 'yt/collections/earnings'
4
4
  describe Yt::Collections::Earnings do
5
5
  subject(:collection) { Yt::Collections::Earnings.new parent: channel }
6
6
  let(:channel) { Yt::Channel.new id: 'UCxO1tY8h1AhOz0T4ENwmpow' }
7
- let(:msg) { {response_body: {error: {errors: [error]}}}.to_json }
8
7
  let(:date) { 1.day.ago.to_date }
9
8
  let(:dollars) { 10 }
10
- let(:message) { 'Invalid query. Query did not conform to the expectations.' }
11
9
  before { expect(collection).to behave }
12
10
 
13
11
  describe '#within' do
@@ -16,43 +14,5 @@ describe Yt::Collections::Earnings do
16
14
 
17
15
  it { expect(collection.within(date..date)[date]).to eq dollars }
18
16
  end
19
-
20
- # NOTE: This test is just a reflection of YouTube irrational behavior
21
- # of raising 400 or 504 error once in a while when retrieving earnings.
22
- # Hopefully this will get fixed and this code (and test) removed.
23
- context 'given YouTube responds to the first request with' do
24
- let(:behave) { receive(:flat_map) do
25
- expect(collection).to receive(:flat_map).and_return [date, dollars]
26
- raise Yt::Error, msg
27
- end}
28
-
29
- context 'an Invalid Query error' do
30
- let(:error) { {reason: 'badRequest', message: message} }
31
-
32
- it { expect(collection.within(date..date)[date]).to eq dollars }
33
- end
34
-
35
- context 'a Backend error' do
36
- let(:error) { {reason: 'backendError', message: 'Backend Error'} }
37
-
38
- it { expect(collection.within(date..date)[date]).to eq dollars }
39
- end
40
- end
41
-
42
- context 'given YouTube responds to the second request with' do
43
- let(:behave) { receive(:flat_map).twice.and_raise Yt::Error, msg }
44
-
45
- context 'an Invalid Query error' do
46
- let(:error) { {reason: 'badRequest', message: message} }
47
-
48
- it { expect{collection.within date..date}.to raise_error Yt::Error }
49
- end
50
-
51
- context 'a Backend error' do
52
- let(:error) { {reason: 'backendError', message: 'Backend Error'} }
53
-
54
- it { expect{collection.within date..date}.to raise_error Yt::Error }
55
- end
56
- end
57
17
  end
58
18
  end
@@ -1,31 +1,74 @@
1
1
  require 'spec_helper'
2
2
  require 'yt/models/request'
3
3
 
4
+
4
5
  describe Yt::Request do
5
- subject(:request) { Yt::Request.new attrs }
6
- let(:attrs) { {host: 'example.com'} }
7
- before { expect(Net::HTTP).to receive(:start).and_return response }
8
- before { allow(response).to receive(:body) }
6
+ subject(:request) { Yt::Request.new host: 'example.com' }
7
+ let(:response) { response_class.new nil, nil, nil }
8
+ let(:response_body) { }
9
+ before { allow(response).to receive(:body).and_return response_body }
10
+ before { expect(Net::HTTP).to receive(:start).once.and_return response }
9
11
 
10
12
  describe '#run' do
11
- context 'given a request that returns a 500 code' do
12
- let(:response) { Net::HTTPServerError.new nil, nil, nil }
13
- it { expect{request.run}.to fail }
14
- end
13
+ context 'given a request that returns' do
14
+ context 'a success code 2XX' do
15
+ let(:response_class) { Net::HTTPOK }
15
16
 
16
- context 'given a request that returns a 401 code' do
17
- let(:response) { Net::HTTPUnauthorized.new nil, nil, nil }
18
- it { expect{request.run}.to fail }
19
- end
17
+ it { expect{request.run}.not_to fail }
18
+ end
20
19
 
21
- context 'given a request that returns a non-2XX code' do
22
- let(:response) { Net::HTTPNotFound.new nil, nil, nil }
23
- it { expect{request.run}.to fail }
24
- end
20
+ context 'an error code 5XX' do
21
+ let(:response_class) { Net::HTTPServerError }
22
+ let(:retry_response) { retry_response_class.new nil, nil, nil }
23
+ before { allow(retry_response).to receive(:body) }
24
+ before { expect(Net::HTTP).to receive(:start).at_least(:once).and_return retry_response }
25
+
26
+ context 'every time' do
27
+ let(:retry_response_class) { Net::HTTPServerError }
28
+
29
+ it { expect{request.run}.to fail }
30
+ end
31
+
32
+ context 'but returns a success code 2XX the second time' do
33
+ let(:retry_response_class) { Net::HTTPOK }
34
+
35
+ it { expect{request.run}.not_to fail }
36
+ end
37
+ end
38
+
39
+ context 'an error code 400 with "Invalid Query" message' do
40
+ let(:response_class) { Net::HTTPBadRequest }
41
+ let(:response_body) { {error: {errors: [message: message]}}.to_json }
42
+ let(:message) { 'Invalid query. Query did not conform to the expectations' }
43
+
44
+ let(:retry_response) { retry_response_class.new nil, nil, nil }
45
+ before { allow(retry_response).to receive(:body) }
46
+ before { expect(Net::HTTP).to receive(:start).at_least(:once).and_return retry_response }
47
+
48
+ context 'every time' do
49
+ let(:retry_response_class) { Net::HTTPBadRequest }
50
+
51
+ it { expect{request.run}.to fail }
52
+ end
53
+
54
+ context 'but returns a success code 2XX the second time' do
55
+ let(:retry_response_class) { Net::HTTPOK }
56
+
57
+ it { expect{request.run}.not_to fail }
58
+ end
59
+ end
60
+
61
+ context 'an error code 401' do
62
+ let(:response_class) { Net::HTTPUnauthorized }
63
+
64
+ it { expect{request.run}.to fail }
65
+ end
66
+
67
+ context 'any other non-2XX error code' do
68
+ let(:response_class) { Net::HTTPNotFound }
25
69
 
26
- context 'given a request that returns a 2XX code' do
27
- let(:response) { Net::HTTPOK.new nil, nil, nil }
28
- it { expect{request.run}.not_to fail }
70
+ it { expect{request.run}.to fail }
71
+ end
29
72
  end
30
73
  end
31
74
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.12
4
+ version: 0.5.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo