rspec-otel 0.0.1 → 0.0.2

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: fa13ed2e866b0e8f13946b28298356ba677c05e0c1939e3dbd1c887dc5c1d5fc
4
- data.tar.gz: 388d62d4c072e238dcb85a4afce75b02bd444a79b78d14dc4e4a891e4dff3a16
3
+ metadata.gz: 2157d604dda12e0b5a3a31d5f43659ef015578f772cb0bd93ac61fafdc8946ee
4
+ data.tar.gz: 5b41c471c61f4fdb603585c52855c350f4e67de3776d7eb5718252b5bc0e875f
5
5
  SHA512:
6
- metadata.gz: 85046ba3269a35fc48aee92cb1b3e3170fbd3a195a4441febc5739da34e2e73dfbf4931f292c33fcbdd0472d7bf21d28389251c1cca0eb95a57c91055b298996
7
- data.tar.gz: 3119c4a902e011a8b801315b0bd9db1064eac49bc86b951cac2ce6916fd84229f475f5517a3feb7b20071ff84bf0b19b31a6aa9028c250515c6023e31cc3da26
6
+ metadata.gz: bf5b6711af8c60e5cd9d2e46c580b6fe59aa87438154b585c77cc55ad4cf12933f1bf7bb9db4f686cadc124e397805fb8a028fb7f7744c86d44d297f5ec46e2d
7
+ data.tar.gz: 4ee5c3e4deed68810dca54d594d7cc6002b9ef4d15133aeb37e5f77deebbd2a0b952308dfd50df60d1ec62c4a68b52ffca8c7e5e97c3de74b885d53f72007cca
data/README.md CHANGED
@@ -28,7 +28,7 @@ end
28
28
 
29
29
  ### Matching the presence of a span
30
30
 
31
- You can match the emission of a span with the `have_emitted_span` matcher:
31
+ You can match the emission of a span with the `emit_span` matcher:
32
32
 
33
33
  ```ruby
34
34
  require 'spec_helper'
@@ -37,7 +37,7 @@ RSpec.describe 'User API' do
37
37
  it 'emits a span' do
38
38
  expect do
39
39
  get :user, id: 1
40
- end.to have_emitted_span('GET /user').with_attributes({'user.id' => '1'})
40
+ end.to emit_span('GET /user').with_attributes({'user.id' => '1'})
41
41
  end
42
42
  end
43
43
  ```
@@ -45,6 +45,11 @@ end
45
45
  Several conditions can be added to the matcher:
46
46
 
47
47
  * `with_attributes` - Will match only the spans with the specified attributes.
48
- * `with_event` - Will match only the spans with the specified event. This condition can be called multiple times with different events.
48
+ * `without_attributes` - Will only match the spans that do not have the specified attributes
49
+ * `with_event` - Will match only the spans with the specified event.
50
+ * `without_event` - Will only match the spans that do not have the specified event
49
51
  * `with_status` - Will match only the spans that have the proper status.
50
52
  * `with_exception` - Will match only the spans that have the specified exception event.
53
+ * `without_exception` - Will match only the spans that do not have the specified exception event.
54
+
55
+ The `*_event` condition can be called multiple times with different events.
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RspecOtel
4
+ module Matchers
5
+ class EmitSpan
6
+ attr_reader :name
7
+
8
+ def initialize(name = nil)
9
+ @name = name
10
+ @filters = [
11
+ ->(span) { span.name == name }
12
+ ]
13
+ end
14
+
15
+ def matches?(block)
16
+ before_spans = []
17
+ if block.respond_to?(:call)
18
+ before_spans = RspecOtel.exporter.finished_spans
19
+ block.call
20
+ end
21
+
22
+ (RspecOtel.exporter.finished_spans - before_spans).each do |span|
23
+ return true if @filters.all? { |f| f.call(span) }
24
+ end
25
+
26
+ false
27
+ end
28
+
29
+ def with_attributes(attributes)
30
+ @filters << lambda do |span|
31
+ attributes_match?(span.attributes, attributes)
32
+ end
33
+
34
+ self
35
+ end
36
+
37
+ def without_attributes(attributes)
38
+ @filters << lambda do |span|
39
+ !attributes_match?(span.attributes, attributes)
40
+ end
41
+
42
+ self
43
+ end
44
+
45
+ def with_event(name, attributes = {})
46
+ @filters << lambda do |span|
47
+ event_match?(span.events, OpenTelemetry::SDK::Trace::Event.new(name, attributes))
48
+ end
49
+ self
50
+ end
51
+
52
+ def without_event(name, attributes = {})
53
+ @filters << lambda do |span|
54
+ !event_match?(span.events, OpenTelemetry::SDK::Trace::Event.new(name, attributes))
55
+ end
56
+ self
57
+ end
58
+
59
+ def with_status(code, description)
60
+ @filters << lambda do |span|
61
+ status_match?(span.status, code, description)
62
+ end
63
+ self
64
+ end
65
+
66
+ def with_exception(exception = nil)
67
+ with_event('exception', exception_attributes(exception))
68
+ end
69
+
70
+ def without_exception(exception = nil)
71
+ without_event('exception', exception_attributes(exception))
72
+ end
73
+
74
+ def failure_message
75
+ "expected span #{name} to have been emitted, but it couldn't be found"
76
+ end
77
+
78
+ def failure_message_when_negated
79
+ "expected span #{name} to not have been emitted"
80
+ end
81
+
82
+ def supports_block_expectations?
83
+ true
84
+ end
85
+
86
+ private
87
+
88
+ def exception_attributes(exception)
89
+ attributes = {}
90
+ unless exception.nil?
91
+ attributes['exception.type'] = exception.class.to_s
92
+ attributes['exception.message'] = exception.message
93
+ end
94
+
95
+ attributes
96
+ end
97
+
98
+ def attributes_match?(span_attributes, attributes)
99
+ attributes.each do |ak, av|
100
+ sa = span_attributes.select do |k, v|
101
+ ak == k && av == v
102
+ end
103
+
104
+ return false if sa.empty?
105
+ end
106
+
107
+ true
108
+ end
109
+
110
+ def status_match?(span_status, code, description)
111
+ code == span_status.code && description == span_status.description
112
+ end
113
+
114
+ def event_match?(span_events, event)
115
+ return true if span_events.nil?
116
+
117
+ se = span_events.select do |s|
118
+ s.name == event.name &&
119
+ attributes_match?(s.attributes, event.attributes || {})
120
+ end
121
+
122
+ !se.empty?
123
+ end
124
+ end
125
+ end
126
+ end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module RspecOtel
4
4
  module Matchers
5
- def have_emitted_span(name) # rubocop:disable Naming/PredicateName
6
- HaveEmittedSpan.new(name)
5
+ def emit_span(name)
6
+ EmitSpan.new(name)
7
7
  end
8
8
  end
9
9
  end
10
10
 
11
- require 'rspec_otel/matchers/have_emitted_span'
11
+ require 'rspec_otel/matchers/emit_span'
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rspec/core'
4
- require 'rspec/expectations'
5
4
 
6
5
  RSpec.configure do |config|
7
6
  config.before(:suite) do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RspecOtel
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-otel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damien MATHIEU
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-13 00:00:00.000000000 Z
11
+ date: 2024-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
42
+ name: rspec-core
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
@@ -63,7 +63,7 @@ files:
63
63
  - README.md
64
64
  - lib/rspec_otel.rb
65
65
  - lib/rspec_otel/matchers.rb
66
- - lib/rspec_otel/matchers/have_emitted_span.rb
66
+ - lib/rspec_otel/matchers/emit_span.rb
67
67
  - lib/rspec_otel/rspec.rb
68
68
  - lib/rspec_otel/version.rb
69
69
  homepage: https://github.com/dmathieu/rspec-otel
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RspecOtel
4
- module Matchers
5
- class HaveEmittedSpan
6
- attr_reader :name
7
-
8
- def initialize(name)
9
- @name = name
10
- @attributes = {}
11
- end
12
-
13
- def matches?(block)
14
- block.call if block.respond_to?(:call)
15
-
16
- RspecOtel.exporter.finished_spans.each do |span|
17
- return true if span.name == name &&
18
- attributes_match?(span.attributes, @attributes) &&
19
- status_match?(span.status, @status) &&
20
- events_match?(span.events, @events)
21
- end
22
-
23
- false
24
- end
25
-
26
- def with_attributes(attributes)
27
- @attributes = attributes
28
- self
29
- end
30
-
31
- def with_event(name, attributes = {})
32
- @events ||= []
33
- @events << OpenTelemetry::SDK::Trace::Event.new(name, attributes)
34
- self
35
- end
36
-
37
- def with_status(code, description)
38
- @status = { code:, description: }
39
- self
40
- end
41
-
42
- def with_exception(exception)
43
- with_event('exception', {
44
- 'exception.type' => exception.class.to_s,
45
- 'exception.message' => exception.message
46
- })
47
- end
48
-
49
- def failure_message
50
- "expected span #{name} to have been emitted, but it couldn't be found"
51
- end
52
-
53
- def failure_message_when_negated
54
- "expected span #{name} to not have been emitted"
55
- end
56
-
57
- def supports_block_expectations?
58
- true
59
- end
60
-
61
- private
62
-
63
- def attributes_match?(span_attributes, attributes)
64
- attributes.each do |ak, av|
65
- sa = span_attributes.select do |k, v|
66
- ak == k && av == v
67
- end
68
-
69
- return false if sa.empty?
70
- end
71
-
72
- true
73
- end
74
-
75
- def status_match?(span_status, status)
76
- status.nil? ||
77
- (status[:code] == span_status.code && status[:description] == span_status.description)
78
- end
79
-
80
- def events_match?(span_events, events)
81
- return true if span_events.nil?
82
-
83
- events.each do |e|
84
- se = span_events.select do |s|
85
- s.name == e.name &&
86
- attributes_match?(s.attributes, e.attributes)
87
- end
88
-
89
- return false if se.empty?
90
- end
91
-
92
- true
93
- end
94
- end
95
- end
96
- end