hastci 0.1.2 → 0.1.3
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 +4 -4
- data/lib/hastci/ack_worker.rb +1 -1
- data/lib/hastci/adapters/rspec/runner.rb +10 -19
- data/lib/hastci/api_client.rb +8 -4
- data/lib/hastci/cli.rb +6 -3
- data/lib/hastci/config.rb +1 -1
- data/lib/hastci/session.rb +2 -2
- data/lib/hastci/task_buffer.rb +19 -13
- data/lib/hastci/version.rb +1 -1
- data/spec/pacts/hastci_rspec-hastci_api.json +56 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c539e7bbcfc1e63ae87f60a4802989e13917dfd260c90f5b4ae034790351bfc5
|
|
4
|
+
data.tar.gz: 3246b32dbd057b5435404c37d1938049e96bbcb27643df0a69cb1f07c4b6d2d6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6fbd3844f3a7791f4ca01a315bce6e999b5431dbe7aeb89e70e897c1ba467664d985943bd50bcd7b71854e4c563624a8fe54001da2f22424371857a71af800c1
|
|
7
|
+
data.tar.gz: 86d5796be2b12d15b5a5b26b9ec57ad8c7862a88cf4d57af663db85164608a49483048eb747c99a4799326d788aa881eed99059c7f3236a24455a077f68f9f32
|
data/lib/hastci/ack_worker.rb
CHANGED
|
@@ -4,7 +4,7 @@ module HastCI
|
|
|
4
4
|
class AckWorker
|
|
5
5
|
DEFAULT_QUEUE_SIZE = 1000
|
|
6
6
|
DEFAULT_FLUSH_TIMEOUT = 10
|
|
7
|
-
EMPTY_QUEUE_POLL_INTERVAL = 0.
|
|
7
|
+
EMPTY_QUEUE_POLL_INTERVAL = 0.5
|
|
8
8
|
SHUTDOWN_TIMEOUT = 10
|
|
9
9
|
|
|
10
10
|
private_constant :DEFAULT_QUEUE_SIZE, :DEFAULT_FLUSH_TIMEOUT, :EMPTY_QUEUE_POLL_INTERVAL,
|
|
@@ -147,27 +147,18 @@ module HastCI
|
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
def build_logs(failed_examples)
|
|
150
|
-
|
|
151
|
-
summary: summary_for(failed_examples),
|
|
152
|
-
failures: failed_examples.map { |example| failure_payload(example) }
|
|
153
|
-
}
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def summary_for(failed_examples)
|
|
157
|
-
return "passed" if failed_examples.empty?
|
|
150
|
+
return [] if failed_examples.empty?
|
|
158
151
|
|
|
159
|
-
|
|
160
|
-
|
|
152
|
+
failed_examples.map do |example|
|
|
153
|
+
exception = example.exception
|
|
161
154
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
backtrace: Array(exception&.backtrace)
|
|
170
|
-
}
|
|
155
|
+
{
|
|
156
|
+
file: example.metadata[:file_path],
|
|
157
|
+
line: example.metadata[:line_number],
|
|
158
|
+
message: exception&.message,
|
|
159
|
+
backtrace: Array(exception&.backtrace)
|
|
160
|
+
}
|
|
161
|
+
end
|
|
171
162
|
end
|
|
172
163
|
|
|
173
164
|
def ordered_task_names(example_groups)
|
data/lib/hastci/api_client.rb
CHANGED
|
@@ -7,6 +7,8 @@ require "uri"
|
|
|
7
7
|
|
|
8
8
|
module HastCI
|
|
9
9
|
class ApiClient
|
|
10
|
+
OriginalNetHTTP = Net::HTTP
|
|
11
|
+
|
|
10
12
|
DEFAULT_MAX_RETRIES = 5
|
|
11
13
|
DEFAULT_INITIAL_BACKOFF = 0.5
|
|
12
14
|
DEFAULT_MAX_BACKOFF = 30
|
|
@@ -28,11 +30,13 @@ module HastCI
|
|
|
28
30
|
|
|
29
31
|
private_constant :API_PATH_PREFIX, :CONNECTION_DEFAULT, :CONNECTION_HEARTBEAT, :CONNECTION_ACK
|
|
30
32
|
|
|
31
|
-
def initialize(config:, sleeper: Kernel.method(:sleep), max_retries: nil, random: Random.new
|
|
33
|
+
def initialize(config:, sleeper: Kernel.method(:sleep), max_retries: nil, random: Random.new,
|
|
34
|
+
http_class: OriginalNetHTTP)
|
|
32
35
|
@config = config
|
|
33
36
|
@max_retries = max_retries || config.api_max_retries || DEFAULT_MAX_RETRIES
|
|
34
37
|
@sleeper = sleeper
|
|
35
38
|
@random = random
|
|
39
|
+
@http_class = http_class
|
|
36
40
|
|
|
37
41
|
@base_url = URI.parse(config.api_base_url)
|
|
38
42
|
@api_key = config.api_key
|
|
@@ -140,7 +144,7 @@ module HastCI
|
|
|
140
144
|
|
|
141
145
|
def get_json(path, pool: CONNECTION_DEFAULT)
|
|
142
146
|
uri = build_uri(path)
|
|
143
|
-
request =
|
|
147
|
+
request = @http_class::Get.new(uri)
|
|
144
148
|
request["Authorization"] = "Bearer #{@api_key}"
|
|
145
149
|
|
|
146
150
|
execute_request(request, pool: pool)
|
|
@@ -148,7 +152,7 @@ module HastCI
|
|
|
148
152
|
|
|
149
153
|
def post_json(path, body, pool: CONNECTION_DEFAULT)
|
|
150
154
|
uri = build_uri(path)
|
|
151
|
-
request =
|
|
155
|
+
request = @http_class::Post.new(uri)
|
|
152
156
|
request["Content-Type"] = "application/json"
|
|
153
157
|
request["Authorization"] = "Bearer #{@api_key}"
|
|
154
158
|
request.body = JSON.generate(body)
|
|
@@ -226,7 +230,7 @@ module HastCI
|
|
|
226
230
|
end
|
|
227
231
|
|
|
228
232
|
def create_connection
|
|
229
|
-
http =
|
|
233
|
+
http = @http_class.new(@base_url.host, @base_url.port)
|
|
230
234
|
http.use_ssl = @base_url.scheme == "https"
|
|
231
235
|
http.open_timeout = DEFAULT_OPEN_TIMEOUT
|
|
232
236
|
http.read_timeout = DEFAULT_READ_TIMEOUT
|
data/lib/hastci/cli.rb
CHANGED
|
@@ -86,12 +86,15 @@ module HastCI
|
|
|
86
86
|
private_class_method :configure_logging
|
|
87
87
|
|
|
88
88
|
# :nocov:
|
|
89
|
-
def self.setup_interrupt_handler(session, err, &on_interrupt)
|
|
89
|
+
def self.setup_interrupt_handler(session, err, signal_enqueuer: nil, &on_interrupt)
|
|
90
90
|
signals = Queue.new
|
|
91
91
|
signal_count = 0
|
|
92
|
+
enqueue_signal = signal_enqueuer || lambda do |queue, signal|
|
|
93
|
+
Thread.new { queue << signal }
|
|
94
|
+
end
|
|
92
95
|
|
|
93
|
-
trap("INT") { signals
|
|
94
|
-
trap("TERM") { signals
|
|
96
|
+
trap("INT") { enqueue_signal.call(signals, "SIGINT") }
|
|
97
|
+
trap("TERM") { enqueue_signal.call(signals, "SIGTERM") }
|
|
95
98
|
|
|
96
99
|
watcher = Thread.new do
|
|
97
100
|
loop do
|
data/lib/hastci/config.rb
CHANGED
data/lib/hastci/session.rb
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module HastCI
|
|
4
4
|
class Session
|
|
5
5
|
DEFAULT_POLL_INTERVAL = 0.5
|
|
6
|
-
DEFAULT_BUFFER_MIN_SIZE =
|
|
7
|
-
DEFAULT_BUFFER_MAX_SIZE =
|
|
6
|
+
DEFAULT_BUFFER_MIN_SIZE = 1
|
|
7
|
+
DEFAULT_BUFFER_MAX_SIZE = 3
|
|
8
8
|
DEFAULT_SEEDING_POLL_INTERVAL = 1.0
|
|
9
9
|
|
|
10
10
|
STOP_REASONS = %i[user_interrupt server_cancelled].freeze
|
data/lib/hastci/task_buffer.rb
CHANGED
|
@@ -54,20 +54,24 @@ module HastCI
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def next_task
|
|
57
|
-
|
|
58
|
-
raise error if error
|
|
59
|
-
|
|
60
|
-
task = @queue.pop
|
|
61
|
-
|
|
62
|
-
if task.nil?
|
|
57
|
+
loop do
|
|
63
58
|
error = @error_collector.first_error
|
|
64
59
|
raise error if error
|
|
65
60
|
|
|
66
|
-
return nil
|
|
67
|
-
|
|
61
|
+
return nil if queue_closed_and_empty?
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
task = @queue.pop(true)
|
|
65
|
+
rescue ThreadError
|
|
66
|
+
@sleeper.call(@poll_interval)
|
|
67
|
+
next
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
return nil if task.nil?
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
signal_prefetch_if_needed
|
|
73
|
+
return task
|
|
74
|
+
end
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
def size
|
|
@@ -84,6 +88,10 @@ module HastCI
|
|
|
84
88
|
|
|
85
89
|
private
|
|
86
90
|
|
|
91
|
+
def queue_closed_and_empty?
|
|
92
|
+
@queue.respond_to?(:closed?) && @queue.closed? && @queue.empty?
|
|
93
|
+
end
|
|
94
|
+
|
|
87
95
|
def signal_prefetch_if_needed
|
|
88
96
|
@mutex.synchronize do
|
|
89
97
|
@prefetch_condition.signal if @queue.size < @min_size
|
|
@@ -117,9 +125,7 @@ module HastCI
|
|
|
117
125
|
|
|
118
126
|
def wait_for_prefetch_signal
|
|
119
127
|
@mutex.synchronize do
|
|
120
|
-
while @running && !@drained && @queue.size >= @min_size
|
|
121
|
-
@prefetch_condition.wait(@mutex, @poll_interval)
|
|
122
|
-
end
|
|
128
|
+
@prefetch_condition.wait(@mutex, @poll_interval) while @running && !@drained && @queue.size >= @min_size
|
|
123
129
|
end
|
|
124
130
|
end
|
|
125
131
|
|
data/lib/hastci/version.rb
CHANGED
|
@@ -373,16 +373,69 @@
|
|
|
373
373
|
"body": {
|
|
374
374
|
"status": "passed",
|
|
375
375
|
"duration_s": 1.5,
|
|
376
|
-
"logs":
|
|
377
|
-
"summary": "1 example, 0 failures",
|
|
378
|
-
"failures": [
|
|
376
|
+
"logs": [
|
|
379
377
|
]
|
|
378
|
+
},
|
|
379
|
+
"matchingRules": {
|
|
380
|
+
"$.path": {
|
|
381
|
+
"match": "regex",
|
|
382
|
+
"regex": "^\\/api\\/v1\\/tasks\\/\\d+\\/acknowledgment$"
|
|
380
383
|
}
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
"response": {
|
|
387
|
+
"status": 200,
|
|
388
|
+
"headers": {
|
|
389
|
+
"Content-Type": "application/json"
|
|
390
|
+
},
|
|
391
|
+
"body": {
|
|
392
|
+
"ok": true
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"description": "a request to ack a task with failures",
|
|
398
|
+
"providerState": "a task exists",
|
|
399
|
+
"request": {
|
|
400
|
+
"method": "post",
|
|
401
|
+
"path": "/api/v1/tasks/101/acknowledgment",
|
|
402
|
+
"headers": {
|
|
403
|
+
"Authorization": "Bearer test-api-key",
|
|
404
|
+
"Content-Type": "application/json"
|
|
405
|
+
},
|
|
406
|
+
"body": {
|
|
407
|
+
"status": "failed",
|
|
408
|
+
"duration_s": 2.0,
|
|
409
|
+
"logs": [
|
|
410
|
+
{
|
|
411
|
+
"file": "spec/models/user_spec.rb",
|
|
412
|
+
"line": 123,
|
|
413
|
+
"message": "Expected 1, got 2",
|
|
414
|
+
"backtrace": [
|
|
415
|
+
"spec/models/user_spec.rb:123:in `block'"
|
|
416
|
+
]
|
|
417
|
+
}
|
|
418
|
+
]
|
|
381
419
|
},
|
|
382
420
|
"matchingRules": {
|
|
383
421
|
"$.path": {
|
|
384
422
|
"match": "regex",
|
|
385
423
|
"regex": "^\\/api\\/v1\\/tasks\\/\\d+\\/acknowledgment$"
|
|
424
|
+
},
|
|
425
|
+
"$.body.logs[0].file": {
|
|
426
|
+
"match": "type"
|
|
427
|
+
},
|
|
428
|
+
"$.body.logs[0].line": {
|
|
429
|
+
"match": "type"
|
|
430
|
+
},
|
|
431
|
+
"$.body.logs[0].message": {
|
|
432
|
+
"match": "type"
|
|
433
|
+
},
|
|
434
|
+
"$.body.logs[0].backtrace": {
|
|
435
|
+
"min": 1
|
|
436
|
+
},
|
|
437
|
+
"$.body.logs[0].backtrace[*].*": {
|
|
438
|
+
"match": "type"
|
|
386
439
|
}
|
|
387
440
|
}
|
|
388
441
|
},
|