@specsage/cli 0.1.12 → 0.1.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.
- package/lib/client_errors.rb +6 -0
- package/lib/runner.rb +12 -7
- package/lib/step_client.rb +8 -1
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Shared base error type for step clients (StepClient, DirectStepClient).
|
|
4
|
+
# Runner can rescue this base type to handle errors from either client.
|
|
5
|
+
# Each client defines its own StepError subclass for API stability.
|
|
6
|
+
class StepClientError < StandardError; end
|
package/lib/runner.rb
CHANGED
|
@@ -11,6 +11,7 @@ require 'fileutils'
|
|
|
11
11
|
# Determine SpecSage home directory for locating resources
|
|
12
12
|
SPECSAGE_HOME ||= File.expand_path('..', __dir__)
|
|
13
13
|
|
|
14
|
+
require_relative 'client_errors'
|
|
14
15
|
require_relative 'step_client'
|
|
15
16
|
|
|
16
17
|
class Runner
|
|
@@ -25,7 +26,8 @@ class Runner
|
|
|
25
26
|
|
|
26
27
|
# Initialize runner with scenario data from server
|
|
27
28
|
# @param all_scenarios [Hash] optional map of scenario_id => scenario_data for pre-scenario lookup
|
|
28
|
-
|
|
29
|
+
# @param step_client [StepClient, DirectStepClient] optional pre-configured client for step processing
|
|
30
|
+
def initialize(scenario_data, visible: false, record: false, publisher: nil, server_run_id: nil, all_scenarios: nil, step_client: nil)
|
|
29
31
|
@scenario = normalize_scenario_data(scenario_data)
|
|
30
32
|
@scenario_id = @scenario['id']
|
|
31
33
|
@scenario_name = @scenario['name'] || @scenario['id'] || 'unnamed'
|
|
@@ -38,7 +40,7 @@ class Runner
|
|
|
38
40
|
@next_request_id = 1
|
|
39
41
|
@node_channel_poisoned = false
|
|
40
42
|
@publisher = publisher
|
|
41
|
-
@step_client = nil
|
|
43
|
+
@step_client = step_client # Accept pre-configured client (nil = create StepClient in run())
|
|
42
44
|
@server_run_id = server_run_id
|
|
43
45
|
@credentials = {} # Credentials received from server { "NAME" => "value" }
|
|
44
46
|
@max_steps = nil # Max browser actions allowed, received from server on first step
|
|
@@ -51,7 +53,10 @@ class Runner
|
|
|
51
53
|
|
|
52
54
|
raise ArgumentError, 'server_run_id is required' unless @server_run_id
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
# Only create StepClient if not injected (CLI path uses HTTP, Sidekiq injects DirectStepClient)
|
|
57
|
+
# TODO: Validate publisher presence here when step_client is nil. Currently crashes with
|
|
58
|
+
# NoMethodError on @publisher.base_url if caller omits both step_client and publisher.
|
|
59
|
+
@step_client ||= StepClient.new(
|
|
55
60
|
base_url: @publisher.base_url,
|
|
56
61
|
server_run_id: @server_run_id,
|
|
57
62
|
api_key: @publisher.api_key
|
|
@@ -124,7 +129,7 @@ class Runner
|
|
|
124
129
|
cleanup_temp_dir
|
|
125
130
|
|
|
126
131
|
result[:verdict]
|
|
127
|
-
rescue
|
|
132
|
+
rescue StepClientError => e
|
|
128
133
|
send_client_verdict_if_needed('ERROR', "Server error: #{e.message}")
|
|
129
134
|
stop_node_process
|
|
130
135
|
upload_video
|
|
@@ -245,7 +250,7 @@ class Runner
|
|
|
245
250
|
status: status,
|
|
246
251
|
reason: reason
|
|
247
252
|
)
|
|
248
|
-
rescue
|
|
253
|
+
rescue StepClientError => e
|
|
249
254
|
log "Warning: Failed to send main scenario verdict: #{e.message}"
|
|
250
255
|
end
|
|
251
256
|
|
|
@@ -587,7 +592,7 @@ class Runner
|
|
|
587
592
|
log "Uploading video (#{@video_data.bytesize} bytes)..."
|
|
588
593
|
@step_client.upload_video(scenario_id: @scenario_id, video_data: @video_data)
|
|
589
594
|
log "Video uploaded successfully."
|
|
590
|
-
rescue
|
|
595
|
+
rescue StepClientError => e
|
|
591
596
|
log "Warning: Failed to upload video: #{e.message}"
|
|
592
597
|
end
|
|
593
598
|
|
|
@@ -641,7 +646,7 @@ class Runner
|
|
|
641
646
|
status: status,
|
|
642
647
|
reason: reason
|
|
643
648
|
)
|
|
644
|
-
rescue
|
|
649
|
+
rescue StepClientError => e
|
|
645
650
|
log "Warning: Failed to send verdict to server: #{e.message}"
|
|
646
651
|
end
|
|
647
652
|
|
package/lib/step_client.rb
CHANGED
|
@@ -7,9 +7,12 @@ require "net/http"
|
|
|
7
7
|
require "uri"
|
|
8
8
|
require "json"
|
|
9
9
|
require "base64"
|
|
10
|
+
require_relative "client_errors"
|
|
10
11
|
|
|
11
12
|
class StepClient
|
|
12
|
-
|
|
13
|
+
# Subclass shared error for API stability (supports subclassing, .class checks, .name)
|
|
14
|
+
# Runner can rescue either StepClient::StepError or the base StepClientError
|
|
15
|
+
class StepError < StepClientError; end
|
|
13
16
|
|
|
14
17
|
attr_reader :server_run_id
|
|
15
18
|
|
|
@@ -59,6 +62,10 @@ class StepClient
|
|
|
59
62
|
|
|
60
63
|
response = post("/api/runs/#{@server_run_id}/step", body)
|
|
61
64
|
|
|
65
|
+
# TODO: Credentials defaulted to {} may change semantics. Server returns nil when no
|
|
66
|
+
# credentials are present (after first step). Returning {} instead of nil may cause
|
|
67
|
+
# downstream code to branch incorrectly (`if credentials` is always truthy). Consider
|
|
68
|
+
# returning nil when server returns nil, or document this as intentional contract.
|
|
62
69
|
{
|
|
63
70
|
action: response["action"],
|
|
64
71
|
step_number: response["step_number"],
|