test_bench-telemetry 2.0.0.0

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/lib/test_bench/telemetry/controls/capture_sink/path.rb +30 -0
  3. data/lib/test_bench/telemetry/controls/capture_sink/record.rb +21 -0
  4. data/lib/test_bench/telemetry/controls/comment.rb +19 -0
  5. data/lib/test_bench/telemetry/controls/detail_level.rb +15 -0
  6. data/lib/test_bench/telemetry/controls/error.rb +36 -0
  7. data/lib/test_bench/telemetry/controls/event.rb +77 -0
  8. data/lib/test_bench/telemetry/controls/events/asserted.rb +32 -0
  9. data/lib/test_bench/telemetry/controls/events/commented.rb +26 -0
  10. data/lib/test_bench/telemetry/controls/events/context_entered.rb +31 -0
  11. data/lib/test_bench/telemetry/controls/events/context_exited.rb +34 -0
  12. data/lib/test_bench/telemetry/controls/events/context_skipped.rb +31 -0
  13. data/lib/test_bench/telemetry/controls/events/detail_decreased.rb +23 -0
  14. data/lib/test_bench/telemetry/controls/events/detail_increased.rb +23 -0
  15. data/lib/test_bench/telemetry/controls/events/error_raised.rb +26 -0
  16. data/lib/test_bench/telemetry/controls/events/file_entered.rb +29 -0
  17. data/lib/test_bench/telemetry/controls/events/file_exited.rb +32 -0
  18. data/lib/test_bench/telemetry/controls/events/fixture_finished.rb +29 -0
  19. data/lib/test_bench/telemetry/controls/events/fixture_started.rb +26 -0
  20. data/lib/test_bench/telemetry/controls/events/run_aborted.rb +29 -0
  21. data/lib/test_bench/telemetry/controls/events/run_finished.rb +32 -0
  22. data/lib/test_bench/telemetry/controls/events/run_started.rb +29 -0
  23. data/lib/test_bench/telemetry/controls/events/test_finished.rb +34 -0
  24. data/lib/test_bench/telemetry/controls/events/test_skipped.rb +31 -0
  25. data/lib/test_bench/telemetry/controls/events/test_started.rb +31 -0
  26. data/lib/test_bench/telemetry/controls/events.rb +27 -0
  27. data/lib/test_bench/telemetry/controls/fixture_name.rb +19 -0
  28. data/lib/test_bench/telemetry/controls/handler.rb +76 -0
  29. data/lib/test_bench/telemetry/controls/line_number.rb +10 -0
  30. data/lib/test_bench/telemetry/controls/path.rb +87 -0
  31. data/lib/test_bench/telemetry/controls/random.rb +7 -0
  32. data/lib/test_bench/telemetry/controls/result.rb +12 -0
  33. data/lib/test_bench/telemetry/controls/sink.rb +11 -0
  34. data/lib/test_bench/telemetry/controls/time.rb +76 -0
  35. data/lib/test_bench/telemetry/controls/title.rb +43 -0
  36. data/lib/test_bench/telemetry/controls.rb +40 -0
  37. data/lib/test_bench/telemetry/event/events.rb +35 -0
  38. data/lib/test_bench/telemetry/event/serialization.rb +143 -0
  39. data/lib/test_bench/telemetry/event/type.rb +27 -0
  40. data/lib/test_bench/telemetry/event.rb +41 -0
  41. data/lib/test_bench/telemetry/sink/capture/path.rb +69 -0
  42. data/lib/test_bench/telemetry/sink/capture/record/generate.rb +49 -0
  43. data/lib/test_bench/telemetry/sink/capture/record.rb +73 -0
  44. data/lib/test_bench/telemetry/sink/capture.rb +55 -0
  45. data/lib/test_bench/telemetry/sink/file.rb +31 -0
  46. data/lib/test_bench/telemetry/sink/handler.rb +90 -0
  47. data/lib/test_bench/telemetry/substitute.rb +65 -0
  48. data/lib/test_bench/telemetry/telemetry.rb +68 -0
  49. data/lib/test_bench/telemetry.rb +19 -0
  50. metadata +118 -0
@@ -0,0 +1,27 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Event
4
+ module Type
5
+ def self.get(class_name)
6
+ *, constant_name = class_name.split('::')
7
+
8
+ constant_name.to_sym
9
+ end
10
+
11
+ def self.method_cased(event_type)
12
+ pascal_cased = event_type.to_s
13
+
14
+ underscore_cased = pascal_cased.gsub(%r{(?:\A|[a-z])[A-Z]+}) do |match_text|
15
+ if ('a'..'z').include?(match_text[0])
16
+ match_text.insert(1, '_')
17
+ end
18
+ match_text.downcase!
19
+ match_text
20
+ end
21
+
22
+ underscore_cased.to_sym
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Event
4
+ def self.define(*attribute_names)
5
+ Struct.new(*attribute_names, :time) do
6
+ include Event
7
+ end
8
+ end
9
+
10
+ def self.included(cls)
11
+ cls.class_exec do
12
+ extend EventType
13
+ end
14
+ end
15
+
16
+ def self.each_event_type(&block)
17
+ Events.constants(false).each(&block)
18
+ end
19
+
20
+ def event_type
21
+ self.class.event_type
22
+ end
23
+
24
+ def dump
25
+ Serialization.dump(self)
26
+ end
27
+
28
+ def self.load(data, event_namespace=nil)
29
+ event_namespace ||= Events
30
+
31
+ Serialization.load(data, event_namespace)
32
+ end
33
+
34
+ module EventType
35
+ def event_type
36
+ @event_type ||= Type.get(name)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,69 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Sink
4
+ class Capture
5
+ class Path
6
+ def segments
7
+ @segments ||= []
8
+ end
9
+ attr_writer :segments
10
+
11
+ def match?(*segments, segment)
12
+ if not segment == self.segments.last
13
+ return false
14
+ end
15
+
16
+ segment_iterator = self.segments.to_enum
17
+
18
+ control_segments = [*segments, segment]
19
+
20
+ control_segments.all? do |control_segment|
21
+ begin
22
+ next_segment = segment_iterator.next
23
+ end until next_segment == control_segment
24
+ true
25
+
26
+ rescue StopIteration
27
+ false
28
+ end
29
+ end
30
+
31
+ def push_segment(segment)
32
+ segments << segment
33
+ end
34
+ alias :push :push_segment
35
+ alias :<< :push
36
+
37
+ def pop_segment(compare_segment=nil)
38
+ segments.pop
39
+ end
40
+ alias :pop :pop_segment
41
+
42
+ def copy(receiver)
43
+ path = self.class.new
44
+
45
+ segments.each do |segment|
46
+ path << segment
47
+ end
48
+
49
+ receiver.path = path
50
+ path
51
+ end
52
+
53
+ def copy?(compare_path)
54
+ eql?(compare_path) && !equal?(compare_path)
55
+ end
56
+
57
+ def eql?(compare)
58
+ if compare.is_a?(self.class)
59
+ segments == compare.segments
60
+ else
61
+ false
62
+ end
63
+ end
64
+ alias :== :eql?
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,49 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Sink
4
+ class Capture
5
+ class Record
6
+ class Generate
7
+ include Event::Events
8
+
9
+ def path
10
+ @path ||= Path.new
11
+ end
12
+ attr_writer :path
13
+
14
+ def detail_level
15
+ @detail_level ||= 0
16
+ end
17
+ attr_writer :detail_level
18
+
19
+ def call(event)
20
+ case event
21
+ when TestStarted, ContextEntered
22
+ path.push(event.title)
23
+ when TestFinished, ContextExited
24
+ path.pop(event.title)
25
+ when DetailIncreased
26
+ self.detail_level += 1
27
+ when DetailDecreased
28
+ self.detail_level -= 1
29
+ end
30
+
31
+ record = Record.build(event, path, detail_level)
32
+
33
+ case event
34
+ when TestFinished, ContextExited
35
+ title = event.title
36
+ record.path.push(title)
37
+ when Commented
38
+ comment = event.comment
39
+ record.path.push(comment)
40
+ end
41
+
42
+ record
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,73 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Sink
4
+ class Capture
5
+ Record = Struct.new(:event, :path, :detail_level) do
6
+ def self.build(event, path, detail_level)
7
+ instance = new
8
+ instance.event = event
9
+ instance.detail_level = detail_level
10
+
11
+ path.copy(instance)
12
+
13
+ instance
14
+ end
15
+
16
+ def match?(*path_segments, detail: nil, detail_level: nil, &block)
17
+ if not path_segments?(*path_segments)
18
+ false
19
+ elsif not detail?(detail)
20
+ false
21
+ elsif not detail_level?(detail_level)
22
+ false
23
+ elsif not block?(&block)
24
+ false
25
+ else
26
+ true
27
+ end
28
+ end
29
+
30
+ def detail_match?(match)
31
+ if match.nil?
32
+ true
33
+ elsif match
34
+ detail_level > 0
35
+ else
36
+ detail_level.zero?
37
+ end
38
+ end
39
+ alias :detail? :detail_match?
40
+
41
+ def detail_level_match?(detail_level)
42
+ if detail_level.nil?
43
+ true
44
+ else
45
+ detail_level == self.detail_level
46
+ end
47
+ end
48
+ alias :detail_level? :detail_level_match?
49
+
50
+ def path_segments_match?(*segments)
51
+ if segments.empty?
52
+ true
53
+ else
54
+ path.match?(*segments)
55
+ end
56
+ end
57
+ alias :path_segments? :path_segments_match?
58
+
59
+ def block_match?(&block)
60
+ if block.nil?
61
+ true
62
+ elsif block.(event.event_type, *event.values)
63
+ true
64
+ else
65
+ false
66
+ end
67
+ end
68
+ alias :block? :block_match?
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,55 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Sink
4
+ class Capture
5
+ include Sink
6
+
7
+ MatchError = Class.new(RuntimeError)
8
+
9
+ def raw_records
10
+ @raw_records ||= []
11
+ end
12
+
13
+ def generate_record
14
+ @generate_record ||= Record::Generate.new
15
+ end
16
+ attr_writer :generate_record
17
+
18
+ def call(event)
19
+ record = generate_record.(event)
20
+
21
+ raw_records.push(record)
22
+
23
+ record
24
+ end
25
+
26
+ def one_record?(...)
27
+ record = one_record(...)
28
+
29
+ !record.nil?
30
+ end
31
+
32
+ def one_record(...)
33
+ records = records(...)
34
+
35
+ if records.count > 1
36
+ raise MatchError, "More than one record matches (Matching Records: #{records.count})"
37
+ end
38
+
39
+ records.first
40
+ end
41
+
42
+ def any_record?(...)
43
+ records(...).any?
44
+ end
45
+ alias :record? :any_record?
46
+
47
+ def records(...)
48
+ raw_records.select do |record|
49
+ record.match?(...)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Sink
4
+ class File
5
+ include Sink
6
+
7
+ attr_reader :io
8
+
9
+ def initialize(io)
10
+ @io = io
11
+ end
12
+
13
+ def self.open(path, &block)
14
+ ::File.open(path, 'w') do |io|
15
+ instance = new(io)
16
+
17
+ block.(instance, io)
18
+
19
+ return instance
20
+ end
21
+ end
22
+
23
+ def call(event)
24
+ data = event.dump
25
+
26
+ io.write(data)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,90 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Sink
4
+ module Handler
5
+ def self.included(cls)
6
+ cls.class_exec do
7
+ include Sink
8
+
9
+ extend HandlerMethod
10
+ extend HandleMacro
11
+
12
+ include Event::Events
13
+ end
14
+ end
15
+
16
+ def handle(event)
17
+ handles = handle?(event)
18
+
19
+ if handles
20
+ handler_method = handler_method(event)
21
+
22
+ parameters = method(handler_method).parameters
23
+
24
+ final_parameter_type, _ = parameters.last
25
+ if not final_parameter_type == :rest
26
+ parameter_count = parameters.count
27
+
28
+ arguments = event.values[0...parameter_count]
29
+ else
30
+ arguments = event.values
31
+ end
32
+
33
+ __send__(handler_method, *arguments)
34
+
35
+ true
36
+ else
37
+ false
38
+ end
39
+ end
40
+ alias :call :handle
41
+
42
+ def handle?(event_or_event_type)
43
+ handler_method = handler_method(event_or_event_type)
44
+
45
+ not handler_method.nil?
46
+ end
47
+
48
+ def handler_method(event_or_event_type)
49
+ handler_method = self.class.handler_method(event_or_event_type)
50
+
51
+ if respond_to?(handler_method)
52
+ handler_method
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ module HandleMacro
59
+ def handle_macro(event_class, &block)
60
+ event_type = event_class
61
+
62
+ handler_method = HandlerMethod.get(event_type)
63
+
64
+ define_method(handler_method, &block)
65
+ end
66
+ alias :handle :handle_macro
67
+ end
68
+
69
+ module HandlerMethod
70
+ def handler_method(event_or_event_type)
71
+ HandlerMethod.get(event_or_event_type)
72
+ end
73
+
74
+ def self.get(event_or_event_type)
75
+ if event_or_event_type.is_a?(Symbol)
76
+ event_type = event_or_event_type
77
+ else
78
+ event = event_or_event_type
79
+ event_type = event.event_type
80
+ end
81
+
82
+ event_type_method_cased = Event::Type.method_cased(event_type)
83
+
84
+ :"handle_#{event_type_method_cased}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,65 @@
1
+ module TestBench
2
+ class Telemetry
3
+ module Substitute
4
+ def self.build
5
+ Telemetry.build
6
+ end
7
+
8
+ class Telemetry < Telemetry
9
+ def capture_sink
10
+ @capture_sink ||= Sink::Capture.new
11
+ end
12
+
13
+ def self.build
14
+ instance = new
15
+ instance.register(instance.capture_sink)
16
+ instance
17
+ end
18
+
19
+ Event.each_event_type do |event_type|
20
+ event_type_method_cased = Event::Type.method_cased(event_type)
21
+
22
+ module_eval(<<~RUBY, __FILE__, __LINE__)
23
+ def one_#{event_type_method_cased}_record?(*arguments, **keyword_arguments, &block)
24
+ one_record?(*arguments, **keyword_arguments) do |compare_event_type, *event_values|
25
+ if compare_event_type == #{event_type.inspect}
26
+ block.(*event_values)
27
+ end
28
+ end
29
+ end
30
+
31
+ def one_#{event_type_method_cased}_record(*arguments, **keyword_arguments, &block)
32
+ one_record(*arguments, **keyword_arguments) do |compare_event_type, *event_values|
33
+ if compare_event_type == #{event_type.inspect}
34
+ block.(*event_values)
35
+ end
36
+ end
37
+ end
38
+
39
+ def any_#{event_type_method_cased}_record?(*arguments, **keyword_arguments, &block)
40
+ any_record?(*arguments, **keyword_arguments) do |compare_event_type, *event_values|
41
+ if compare_event_type == #{event_type.inspect}
42
+ block.(*event_values)
43
+ end
44
+ end
45
+ end
46
+ alias :#{event_type_method_cased}_record? :any_#{event_type_method_cased}_record?
47
+
48
+ def #{event_type_method_cased}_records(*arguments, **keyword_arguments, &block)
49
+ records(*arguments, **keyword_arguments) do |compare_event_type, *event_values|
50
+ if compare_event_type == #{event_type.inspect}
51
+ block.(*event_values)
52
+ end
53
+ end
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ def one_record?(...) = capture_sink.one_record?(...)
59
+ def one_record(...) = capture_sink.one_record(...)
60
+ def any_record?(...) = capture_sink.any_record?(...)
61
+ def records(...) = capture_sink.records(...)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,68 @@
1
+ module TestBench
2
+ class Telemetry
3
+ include Event::Events
4
+
5
+ RegistrationError = Class.new(RuntimeError)
6
+
7
+ def sinks
8
+ @sinks ||= []
9
+ end
10
+
11
+ def self.build(*sinks)
12
+ instance = new
13
+
14
+ sinks.each do |sink|
15
+ instance.register(sink)
16
+ end
17
+
18
+ instance
19
+ end
20
+
21
+ def self.configure(receiver, *sinks, attr_name: nil)
22
+ attr_name ||= :telemetry
23
+
24
+ instance = build(*sinks)
25
+ receiver.public_send(:"#{attr_name}=", instance)
26
+ end
27
+
28
+ def record(event, now=nil)
29
+ event.time ||= current_time(now)
30
+
31
+ sinks.each do |sink|
32
+ sink.(event)
33
+ end
34
+
35
+ event
36
+ end
37
+
38
+ def register(sink)
39
+ if registered?(sink)
40
+ raise RegistrationError, "Already registered #{sink.inspect}"
41
+ end
42
+
43
+ sinks << sink
44
+ end
45
+
46
+ def registered?(sink)
47
+ sinks.include?(sink)
48
+ end
49
+
50
+ Event.each_event_type do |event_type|
51
+ event_class = Event.const_get(event_type)
52
+
53
+ event_type_method_cased = Event::Type.method_cased(event_type)
54
+
55
+ module_eval(<<~RUBY, __FILE__, __LINE__)
56
+ def record_#{event_type_method_cased}(*values)
57
+ event = #{event_class}.new(*values)
58
+
59
+ record(event)
60
+ end
61
+ RUBY
62
+ end
63
+
64
+ def current_time(now)
65
+ now || ::Time.now
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_bench/random'
2
+
3
+ require 'test_bench/telemetry/event'
4
+ require 'test_bench/telemetry/event/type'
5
+ require 'test_bench/telemetry/event/serialization'
6
+ require 'test_bench/telemetry/event/events'
7
+
8
+ require 'test_bench/telemetry/sink/handler'
9
+
10
+ require 'test_bench/telemetry/sink/capture/path'
11
+ require 'test_bench/telemetry/sink/capture/record'
12
+ require 'test_bench/telemetry/sink/capture/record/generate'
13
+ require 'test_bench/telemetry/sink/capture'
14
+
15
+ require 'test_bench/telemetry/sink/file'
16
+
17
+ require 'test_bench/telemetry/telemetry'
18
+
19
+ require 'test_bench/telemetry/substitute'