knapsack_pro 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 406093c37a1985ce7cf5b2c89f625a226c4d42d8c4554eaac9037901fcfc3707
4
- data.tar.gz: b299828d599720303c5203caee6bebe3d5b96e122fbf878924ac00c6cf4b6db2
3
+ metadata.gz: 59483963a5cda7dabf89075bf4aebff864e813d0192db2c10e8162918ecbef11
4
+ data.tar.gz: c4e50a75d402de63289db9b6126df9f6fbced9a562776125d94903752961b10a
5
5
  SHA512:
6
- metadata.gz: aa7533794502874dee1c1275197166f99a5cb8ff63e3e37736fc4c2d66586af7a53088ca4a3a194f54a50a94d62c071253f421255a608bf9250cb5a9521bd3ef
7
- data.tar.gz: 59b4abd2a72a5f979aa0dbde8cab8a62f1e8c06f37415bba258649ae6c9d7e373cdbe131514e7ad2f7b6870b8251a3c25ae50c37fd1847650e1761802ce39378
6
+ metadata.gz: b8341410b23dc56c9843734d6f264dc679eca71e8cda951f5594f782433f2c20b7998b708d21b8e76616a41b1cc5b14d4d80d9e468c61bc015edd605aac2a9b1
7
+ data.tar.gz: df0e11899060062d5ad447f749263ce05ab4c7dd11b93cbcb837e3c380c9879a08ee247292c9fed32839d17b13ac8a6b696493032b71d92d3d6d914b458eeed0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ### 1.6.0
4
+
5
+ * Retry request 3 times when API returns 5xx HTTP status
6
+
7
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/78
8
+
9
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v1.5.0...v1.6.0
10
+
3
11
  ### 1.5.0
4
12
 
5
13
  * Add support for Semaphore CI 2.0
data/README.md CHANGED
@@ -144,6 +144,7 @@ You can see list of questions for common problems and tips in below [Table of Co
144
144
  - [for knapack_pro regular mode](#for-knapack_pro-regular-mode-1)
145
145
  - [for knapsack_pro queue mode](#for-knapsack_pro-queue-mode-1)
146
146
  - [How can I change log level?](#how-can-i-change-log-level)
147
+ - [How to write knapack_pro logs to a file?](#how-to-write-knapack_pro-logs-to-a-file)
147
148
  - [How to split tests based on test level instead of test file level?](#how-to-split-tests-based-on-test-level-instead-of-test-file-level)
148
149
  - [A. Create multiple small test files](#a-create-multiple-small-test-files)
149
150
  - [B. Use tags to mark set of tests in particular test file](#b-use-tags-to-mark-set-of-tests-in-particular-test-file)
@@ -1752,6 +1753,36 @@ Recommended log levels you can use:
1752
1753
  * `debug` is default log level and it is recommended to log details about requests to Knapsack Pro API. Thanks to that you can debug things or ensure everything works. For instance in [user dashboard](https://knapsackpro.com/dashboard) you can find tips referring to debug logs.
1753
1754
  * `info` level shows message like how to retry tests in development or info why something works this way or the other (for instance why tests were not executed on the CI node). You can use `info` level when you really don't want to see all debug messages from default log level.
1754
1755
 
1756
+ #### How to write knapack_pro logs to a file?
1757
+
1758
+ In your `rails_helper.rb` or `spec_helper.rb` you can set custom Knapsack Pro logger and write to custom log file.
1759
+
1760
+ ```ruby
1761
+ require 'logger'
1762
+ KnapsackPro.logger = Logger.new(Rails.root.join('log', "knapsack_pro_node_#{KnapsackPro::Config::Env.ci_node_index}.log"))
1763
+ KnapsackPro.logger.level = Logger::DEBUG
1764
+ ```
1765
+
1766
+ Note if you run knapsack_pro in Queue Mode then the very first request to Knapsack Pro API still will be shown to stdout because we need to have set of test files needed to run RSpec before we load `rails_helper.rb`/`spec_helper.rb` where the configuration of logger actually is loaded for the first time.
1767
+
1768
+ If you would like to keep knapsack_pro logs after your CI build finished then you could use artifacts or some cache mechanize for your CI provider.
1769
+
1770
+ For instance, for [CircleCI 2.0 artifacts](https://circleci.com/docs/2.0/artifacts/) you can specify log directory:
1771
+
1772
+ ```yaml
1773
+ - run:
1774
+ name: RSpec via knapsack_pro Queue Mode
1775
+ command: |
1776
+ # export word is important here!
1777
+ export RAILS_ENV=test
1778
+ bundle exec rake "knapsack_pro:queue:rspec[--format documentation]"
1779
+
1780
+ - store_artifacts:
1781
+ path: log
1782
+ ```
1783
+
1784
+ Now you can preview logs in `Artifacts` tab in the Circle CI build view.
1785
+
1755
1786
  #### How to split tests based on test level instead of test file level?
1756
1787
 
1757
1788
  If you want to split one big test file (test file with long time execution) across multiple CI nodes then you can:
@@ -1,7 +1,10 @@
1
1
  module KnapsackPro
2
2
  module Client
3
3
  class Connection
4
+ class ServerError < StandardError; end
5
+
4
6
  TIMEOUT = 15
7
+ MAX_RETRY = 3
5
8
  REQUEST_RETRY_TIMEBOX = 2
6
9
 
7
10
  def initialize(action)
@@ -23,6 +26,11 @@ module KnapsackPro
23
26
  !!(response_body && (response_body['errors'] || response_body['error']))
24
27
  end
25
28
 
29
+ def server_error?
30
+ status = http_response.code.to_i
31
+ status >= 500 && status < 600
32
+ end
33
+
26
34
  private
27
35
 
28
36
  attr_reader :action, :http_response, :response_body
@@ -91,7 +99,7 @@ module KnapsackPro
91
99
  @http_response = http.post(uri.path, request_body, json_headers)
92
100
  @response_body = parse_response_body(http_response.body)
93
101
 
94
- request_uuid = http_response.header['X-Request-Id']
102
+ request_uuid = http_response.header['X-Request-Id'] || 'N/A'
95
103
 
96
104
  logger.debug("API request UUID: #{request_uuid}")
97
105
  logger.debug("Test suite split seed: #{seed}") if has_seed?
@@ -102,15 +110,21 @@ module KnapsackPro
102
110
  logger.debug(response_body)
103
111
  end
104
112
 
113
+ if server_error?
114
+ raise ServerError.new(response_body)
115
+ end
116
+
105
117
  response_body
106
- rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::EPIPE, EOFError, SocketError, Net::OpenTimeout, Net::ReadTimeout => e
118
+ rescue ServerError, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::EPIPE, EOFError, SocketError, Net::OpenTimeout, Net::ReadTimeout => e
107
119
  logger.warn(e.inspect)
108
120
  retries += 1
109
- if retries < 3
121
+ if retries < MAX_RETRY
110
122
  wait = retries * REQUEST_RETRY_TIMEBOX
111
123
  logger.warn("Wait #{wait}s and retry request to Knapsack Pro API.")
112
- sleep wait
124
+ Kernel.sleep(wait)
113
125
  retry
126
+ else
127
+ response_body
114
128
  end
115
129
  end
116
130
  end
@@ -1,3 +1,3 @@
1
1
  module KnapsackPro
2
- VERSION = '1.5.0'
2
+ VERSION = '1.6.0'
3
3
  end
@@ -68,27 +68,6 @@ describe KnapsackPro::Client::Connection do
68
68
  end
69
69
  end
70
70
 
71
- context 'when body response is json and API response code is 500' do
72
- let(:body) { '{"error": "Internal Server Error"}' }
73
- let(:code) { '500' } # it must be string code
74
-
75
- before do
76
- expect(KnapsackPro).to receive(:logger).exactly(3).and_return(logger)
77
- expect(logger).to receive(:debug).with('API request UUID: fake-uuid')
78
- expect(logger).to receive(:debug).with('API response:')
79
- end
80
-
81
- it do
82
- parsed_response = { 'error' => 'Internal Server Error' }
83
-
84
- expect(logger).to receive(:error).with(parsed_response)
85
-
86
- expect(subject).to eq(parsed_response)
87
- expect(connection.success?).to be false
88
- expect(connection.errors?).to be true
89
- end
90
- end
91
-
92
71
  context 'when body response is json with build_distribution_id' do
93
72
  let(:body) { '{"build_distribution_id": "seed-uuid"}' }
94
73
  let(:code) { '200' } # it must be string code
@@ -130,6 +109,61 @@ describe KnapsackPro::Client::Connection do
130
109
  end
131
110
  end
132
111
  end
112
+
113
+ context 'when retry request for http method POST' do
114
+ before do
115
+ http = instance_double(Net::HTTP)
116
+
117
+ expect(Net::HTTP).to receive(:new).exactly(3).with('api.knapsackpro.test', 3000).and_return(http)
118
+
119
+ expect(http).to receive(:use_ssl=).exactly(3).with(false)
120
+ expect(http).to receive(:open_timeout=).exactly(3).with(15)
121
+ expect(http).to receive(:read_timeout=).exactly(3).with(15)
122
+
123
+ header = { 'X-Request-Id' => 'fake-uuid' }
124
+ http_response = instance_double(Net::HTTPOK, body: body, header: header, code: code)
125
+ expect(http).to receive(:post).exactly(3).with(
126
+ endpoint_path,
127
+ "{\"fake\":\"hash\",\"test_suite_token\":\"3fa64859337f6e56409d49f865d13fd7\"}",
128
+ {
129
+ 'Content-Type' => 'application/json',
130
+ 'Accept' => 'application/json',
131
+ 'KNAPSACK-PRO-CLIENT-NAME' => 'knapsack_pro-ruby',
132
+ 'KNAPSACK-PRO-CLIENT-VERSION' => KnapsackPro::VERSION,
133
+ }
134
+ ).and_return(http_response)
135
+ end
136
+
137
+ context 'when body response is json and API response code is 500' do
138
+ let(:body) { '{"error": "Internal Server Error"}' }
139
+ let(:code) { '500' } # it must be string code
140
+
141
+ before do
142
+ expect(KnapsackPro).to receive(:logger).at_least(1).and_return(logger)
143
+ expect(logger).to receive(:debug).exactly(3).with('API request UUID: fake-uuid')
144
+ expect(logger).to receive(:debug).exactly(3).with('API response:')
145
+ end
146
+
147
+ it do
148
+ parsed_response = { 'error' => 'Internal Server Error' }
149
+
150
+ expect(logger).to receive(:error).exactly(3).with(parsed_response)
151
+
152
+ server_error = described_class::ServerError.new(parsed_response)
153
+ expect(logger).to receive(:warn).exactly(3).with(server_error.inspect)
154
+
155
+ expect(logger).to receive(:warn).with("Wait 2s and retry request to Knapsack Pro API.")
156
+ expect(logger).to receive(:warn).with("Wait 4s and retry request to Knapsack Pro API.")
157
+ expect(Kernel).to receive(:sleep).with(2)
158
+ expect(Kernel).to receive(:sleep).with(4)
159
+
160
+ expect(subject).to eq(parsed_response)
161
+
162
+ expect(connection.success?).to be false
163
+ expect(connection.errors?).to be true
164
+ end
165
+ end
166
+ end
133
167
  end
134
168
 
135
169
  describe '#success?' do
@@ -220,4 +254,37 @@ describe KnapsackPro::Client::Connection do
220
254
  end
221
255
  end
222
256
  end
257
+
258
+ describe '#server_error?' do
259
+ subject { connection.server_error? }
260
+
261
+ before do
262
+ http_response = double(code: code)
263
+ allow(connection).to receive(:http_response).and_return(http_response)
264
+ end
265
+
266
+ context 'when response code is 200' do
267
+ let(:code) { '200' } # it must be string code
268
+
269
+ it { should be false }
270
+ end
271
+
272
+ context 'when response code is 300' do
273
+ let(:code) { '300' } # it must be string code
274
+
275
+ it { should be false }
276
+ end
277
+
278
+ context 'when response code is 400' do
279
+ let(:code) { '400' } # it must be string code
280
+
281
+ it { should be false }
282
+ end
283
+
284
+ context 'when response code is 500' do
285
+ let(:code) { '500' } # it must be string code
286
+
287
+ it { should be true }
288
+ end
289
+ end
223
290
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knapsack_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ArturT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-14 00:00:00.000000000 Z
11
+ date: 2019-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake