bitfab 0.38.1 → 0.38.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/bitfab/client.rb +47 -17
- data/lib/bitfab/mock_override.rb +14 -6
- data/lib/bitfab/span_context.rb +3 -1
- data/lib/bitfab/timestamp.rb +16 -0
- data/lib/bitfab/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28a82b98d8327aead543061c18b95a22b2100f89e0289ffdd6ad85a262e08447
|
|
4
|
+
data.tar.gz: 18c101e18d509cc2a5fb880210d3d5cfaee0f9311c7521abeaa2716bdeca563f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 960e4f390e26e953cb555a1a359fd7e3b505172a74e513fe69f281dc7e1111b03e8ac93451154d632dd225e36cdf33f5c54dc3dc59dbd7379a7af3672f7fb87b
|
|
7
|
+
data.tar.gz: ac599caf319a0dc2814147faee28efd5940609bdc2200d696db4bcb3581fc72fafe443bb50f65204ffb46eea5fa8f0ff9806dd78c42a8d3599e1429263d2ab71
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative "http_client"
|
|
|
8
8
|
require_relative "replay"
|
|
9
9
|
require_relative "span_context"
|
|
10
10
|
require_relative "serialize"
|
|
11
|
+
require_relative "timestamp"
|
|
11
12
|
require_relative "warn_once"
|
|
12
13
|
|
|
13
14
|
module Bitfab
|
|
@@ -122,14 +123,15 @@ module Bitfab
|
|
|
122
123
|
# traces were captured. Receives (args, kwargs, ctx) where ctx is
|
|
123
124
|
# { original_trace_id:, original_span_id: } (with deprecated
|
|
124
125
|
# source_trace_id/source_span_id aliases), and returns [new_args, new_kwargs].
|
|
125
|
-
# @param mock_override [Hash, Array<Hash>, nil] optional selective
|
|
126
|
-
# override(s),
|
|
126
|
+
# @param mock_override [Hash, Proc, Array<Hash, Proc>, nil] optional selective
|
|
127
|
+
# mock override(s), as { match:, value: } hashes or global resolvers. match is a callable:
|
|
127
128
|
# match.call(node) selects spans to substitute (node is
|
|
128
129
|
# { trace_function_key:, span_name:, type:, original_span_id: }). value is
|
|
129
130
|
# EITHER a flat value injected directly OR a callable invoked with
|
|
130
131
|
# { node:, inputs:, kwargs:, get_original_output: }; its result becomes
|
|
131
132
|
# the span's output (full replacement), so downstream real code runs against it. The
|
|
132
|
-
# first matching override
|
|
133
|
+
# first matching override that does not return NO_MOCK_OVERRIDE wins.
|
|
134
|
+
# Per-call overrides take precedence over
|
|
133
135
|
# those registered via register_mock_override, and both take precedence
|
|
134
136
|
# over the base mock strategy. The root span is never overridden.
|
|
135
137
|
# @param db_branch [Boolean, Hash, nil] +true+ or a Hash enables database
|
|
@@ -169,10 +171,9 @@ module Bitfab
|
|
|
169
171
|
# clear_mock_overrides to reset. Per-call replay(mock_override:) overrides
|
|
170
172
|
# take precedence, and both take precedence over the base mock strategy.
|
|
171
173
|
#
|
|
172
|
-
# Accepts
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
# with the ctx hash.
|
|
174
|
+
# Accepts the (match, value) positional form, the keyword/hash form, one
|
|
175
|
+
# global resolver callable, or (trace_function_key, override_or_resolver).
|
|
176
|
+
# A resolver can return Bitfab::NO_MOCK_OVERRIDE to decline the span.
|
|
176
177
|
#
|
|
177
178
|
# @example keyword form (primary), flat value
|
|
178
179
|
# client.register_mock_override(
|
|
@@ -186,19 +187,43 @@ module Bitfab
|
|
|
186
187
|
# ->(ctx) { {label: "refund", inputs: ctx[:inputs]} }
|
|
187
188
|
# )
|
|
188
189
|
#
|
|
189
|
-
# @param positional [Array]
|
|
190
|
-
#
|
|
190
|
+
# @param positional [Array] a (match, value) pair, one { match:, value: }
|
|
191
|
+
# hash, one global resolver, or a trace function key followed by a
|
|
192
|
+
# resolver or override hash
|
|
191
193
|
# @param match [#call, nil] keyword form matcher
|
|
192
194
|
# @param value [Object, #call, nil] keyword form injected value or producer
|
|
193
195
|
# @return [void]
|
|
194
196
|
def register_mock_override(*positional, match: nil, value: VALUE_UNSET)
|
|
195
197
|
if match.nil? && value.equal?(VALUE_UNSET)
|
|
196
|
-
if positional.length ==
|
|
198
|
+
if positional.length == 2 && positional[0].is_a?(String)
|
|
199
|
+
trace_function_key, keyed_override = positional
|
|
200
|
+
if keyed_override.is_a?(Hash) && keyed_override[:match].respond_to?(:call) && keyed_override.key?(:value)
|
|
201
|
+
keyed_match = keyed_override[:match]
|
|
202
|
+
@mock_overrides << {
|
|
203
|
+
match: ->(node) { node[:trace_function_key] == trace_function_key && keyed_match.call(node) },
|
|
204
|
+
value: keyed_override[:value]
|
|
205
|
+
}
|
|
206
|
+
return nil
|
|
207
|
+
end
|
|
208
|
+
if keyed_override.respond_to?(:call)
|
|
209
|
+
@mock_overrides << {
|
|
210
|
+
match: ->(node) { node[:trace_function_key] == trace_function_key },
|
|
211
|
+
value: keyed_override
|
|
212
|
+
}
|
|
213
|
+
return nil
|
|
214
|
+
end
|
|
215
|
+
raise ArgumentError,
|
|
216
|
+
"register_mock_override(trace_function_key, override) requires " \
|
|
217
|
+
"a { match:, value: } hash or callable resolver."
|
|
218
|
+
elsif positional.length == 1 && positional[0].is_a?(Hash)
|
|
197
219
|
override = positional[0]
|
|
198
220
|
match = override[:match]
|
|
199
221
|
# Distinguish an omitted :value from an explicit `value: nil`: the
|
|
200
222
|
# key's presence, not a nil read, is what marks it provided.
|
|
201
223
|
value = override.key?(:value) ? override[:value] : VALUE_UNSET
|
|
224
|
+
elsif positional.length == 1 && positional[0].respond_to?(:call)
|
|
225
|
+
@mock_overrides << {match: ->(_) { true }, value: positional[0]}
|
|
226
|
+
return nil
|
|
202
227
|
elsif positional.length == 2
|
|
203
228
|
match, value = positional
|
|
204
229
|
end
|
|
@@ -309,7 +334,7 @@ module Bitfab
|
|
|
309
334
|
span_id = SecureRandom.uuid
|
|
310
335
|
parent_span_id = parent&.dig(:span_id)
|
|
311
336
|
is_root_span = parent_span_id.nil?
|
|
312
|
-
started_at =
|
|
337
|
+
started_at = Bitfab.now_iso_timestamp
|
|
313
338
|
resolved_test_run_id = replay_ctx&.dig(:test_run_id)
|
|
314
339
|
resolved_input_source_span_id = replay_ctx&.dig(:input_source_span_id)
|
|
315
340
|
resolved_input_source_trace_id = replay_ctx&.dig(:input_source_trace_id)
|
|
@@ -388,7 +413,7 @@ module Bitfab
|
|
|
388
413
|
finalized = true
|
|
389
414
|
|
|
390
415
|
begin
|
|
391
|
-
ended_at =
|
|
416
|
+
ended_at = Bitfab.now_iso_timestamp
|
|
392
417
|
|
|
393
418
|
send_span(
|
|
394
419
|
trace_function_key:,
|
|
@@ -782,8 +807,9 @@ module Bitfab
|
|
|
782
807
|
type: span_type,
|
|
783
808
|
original_span_id: mock_entry && mock_entry[:source_span_id]
|
|
784
809
|
}
|
|
785
|
-
|
|
786
|
-
|
|
810
|
+
overrides.each do |override|
|
|
811
|
+
next unless override[:match].call(node)
|
|
812
|
+
|
|
787
813
|
value = override[:value]
|
|
788
814
|
# value is EITHER a flat value (injected directly) OR a callable
|
|
789
815
|
# invoked with the ctx hash. The result IS the span's output (full
|
|
@@ -791,7 +817,10 @@ module Bitfab
|
|
|
791
817
|
# override always injects, execute_span short-circuits even when this
|
|
792
818
|
# is nil (nil != MOCK_REPLAY_MISS). To inject a proc as the literal
|
|
793
819
|
# output, wrap it in a callable value.
|
|
794
|
-
|
|
820
|
+
unless value.respond_to?(:call)
|
|
821
|
+
return [value, "override"] unless value.equal?(NO_MOCK_OVERRIDE)
|
|
822
|
+
next
|
|
823
|
+
end
|
|
795
824
|
|
|
796
825
|
get_original_output = lambda do
|
|
797
826
|
unless mock_entry
|
|
@@ -799,7 +828,8 @@ module Bitfab
|
|
|
799
828
|
end
|
|
800
829
|
resolve_recorded_output(mock_entry, replay_ctx)
|
|
801
830
|
end
|
|
802
|
-
|
|
831
|
+
resolved = value.call({node:, inputs: args, kwargs:, get_original_output:})
|
|
832
|
+
return [resolved, "override"] unless resolved.equal?(NO_MOCK_OVERRIDE)
|
|
803
833
|
end
|
|
804
834
|
end
|
|
805
835
|
|
|
@@ -860,7 +890,7 @@ module Bitfab
|
|
|
860
890
|
def send_mocked_span(trace_function_key:, trace_id:, span_id:, parent_span_id:,
|
|
861
891
|
span_name:, span_type:, function_name:, args:, kwargs:, mocked_output:,
|
|
862
892
|
started_at:, test_run_id:, input_source_span_id:, mock_source:)
|
|
863
|
-
ended_at =
|
|
893
|
+
ended_at = Bitfab.now_iso_timestamp
|
|
864
894
|
send_span(
|
|
865
895
|
trace_function_key:,
|
|
866
896
|
trace_id:,
|
data/lib/bitfab/mock_override.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Bitfab
|
|
4
|
+
# Return from an override resolver to continue to the next override and then
|
|
5
|
+
# the replay's base mock strategy.
|
|
6
|
+
NO_MOCK_OVERRIDE = Object.new.freeze
|
|
7
|
+
|
|
4
8
|
# Selective mock overrides for replay. Mirrors the TypeScript SDK's
|
|
5
9
|
# mockOverride feature.
|
|
6
10
|
#
|
|
@@ -10,8 +14,10 @@ module Bitfab
|
|
|
10
14
|
# substituted output. This is a third mock mode alongside "run real code" and
|
|
11
15
|
# "replay recorded output" (see MOCK_STRATEGIES in replay.rb).
|
|
12
16
|
#
|
|
13
|
-
# An override is a (match, value) pair
|
|
14
|
-
#
|
|
17
|
+
# An override is a (match, value) pair represented as { match:, value: }, or
|
|
18
|
+
# one global resolver invoked for every child span. A resolver can route on
|
|
19
|
+
# ctx[:node][:trace_function_key] and return Bitfab::NO_MOCK_OVERRIDE to
|
|
20
|
+
# decline the current span.
|
|
15
21
|
#
|
|
16
22
|
# - match is a callable (proc/lambda): match.call(node) -> boolean. node is a
|
|
17
23
|
# structural-metadata hash { trace_function_key:, span_name:, type:,
|
|
@@ -38,9 +44,8 @@ module Bitfab
|
|
|
38
44
|
module MockOverride
|
|
39
45
|
module_function
|
|
40
46
|
|
|
41
|
-
# Normalize the per-call `mock_override` option (
|
|
42
|
-
#
|
|
43
|
-
# order is preserved.
|
|
47
|
+
# Normalize the per-call `mock_override` option (an override hash, a global
|
|
48
|
+
# resolver callable, an array, or nil) into an ordered override array.
|
|
44
49
|
#
|
|
45
50
|
# Each override is validated: it must be a hash with a callable `:match` and
|
|
46
51
|
# must include a `:value` key. A forgotten `:value` raises rather than
|
|
@@ -49,12 +54,15 @@ module Bitfab
|
|
|
49
54
|
# `register_mock_override`, and the Python/TypeScript SDKs, where the per-call
|
|
50
55
|
# override object requires a value.
|
|
51
56
|
#
|
|
52
|
-
# @param mock_override [Hash, Array<Hash>, nil]
|
|
57
|
+
# @param mock_override [Hash, Proc, Array<Hash, Proc>, nil]
|
|
53
58
|
# @return [Array<Hash>]
|
|
54
59
|
def normalize(mock_override)
|
|
55
60
|
return [] if mock_override.nil?
|
|
56
61
|
|
|
57
62
|
overrides = mock_override.is_a?(Array) ? mock_override : [mock_override]
|
|
63
|
+
overrides = overrides.map do |override|
|
|
64
|
+
override.respond_to?(:call) ? {match: ->(_) { true }, value: override} : override
|
|
65
|
+
end
|
|
58
66
|
overrides.each do |override|
|
|
59
67
|
unless override.is_a?(Hash) && override[:match].respond_to?(:call)
|
|
60
68
|
raise ArgumentError,
|
data/lib/bitfab/span_context.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "timestamp"
|
|
4
|
+
|
|
3
5
|
module Bitfab
|
|
4
6
|
# Handle to the current active span, allowing context to be added.
|
|
5
7
|
class CurrentSpan
|
|
@@ -171,7 +173,7 @@ module Bitfab
|
|
|
171
173
|
def create(trace_id, test_run_id: nil, input_source_trace_id: nil)
|
|
172
174
|
@states_mutex.synchronize do
|
|
173
175
|
@states[trace_id] ||= begin
|
|
174
|
-
started_at =
|
|
176
|
+
started_at = Bitfab.now_iso_timestamp
|
|
175
177
|
{
|
|
176
178
|
trace_id:,
|
|
177
179
|
started_at:,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
module Bitfab
|
|
6
|
+
@timestamp_mutex = Mutex.new
|
|
7
|
+
@last_timestamp_us = 0
|
|
8
|
+
|
|
9
|
+
def self.now_iso_timestamp
|
|
10
|
+
wall_clock_us = (Time.now.to_r * 1_000_000).to_i
|
|
11
|
+
timestamp_us = @timestamp_mutex.synchronize do
|
|
12
|
+
@last_timestamp_us = [wall_clock_us, @last_timestamp_us + 1].max
|
|
13
|
+
end
|
|
14
|
+
Time.at(Rational(timestamp_us, 1_000_000)).utc.strftime("%Y-%m-%dT%H:%M:%S.%6NZ")
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/bitfab/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bitfab
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.38.
|
|
4
|
+
version: 0.38.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Harvest Team
|
|
@@ -153,6 +153,7 @@ files:
|
|
|
153
153
|
- lib/bitfab/replay_registry.rb
|
|
154
154
|
- lib/bitfab/serialize.rb
|
|
155
155
|
- lib/bitfab/span_context.rb
|
|
156
|
+
- lib/bitfab/timestamp.rb
|
|
156
157
|
- lib/bitfab/traceable.rb
|
|
157
158
|
- lib/bitfab/transport.rb
|
|
158
159
|
- lib/bitfab/version.rb
|