|
1 | 1 | require 'datadog/appsec/stack_trace'
|
2 | 2 | require 'support/thread_backtrace_helpers'
|
3 | 3 |
|
4 |
| -RSpec.describe Datadog::AppSec::StackTrace do |
5 |
| - subject(:dd_stack_trace) { described_class.new(id, stack_trace, message: message) } |
| 4 | +RSpec.describe Datadog::AppSec::StackTrace::Collection do |
| 5 | + subject(:collection) { described_class.new(frames) } |
6 | 6 |
|
7 | 7 | before do
|
8 | 8 | Datadog.configure do |c|
|
9 |
| - c.appsec.stack_trace.enabled = stack_trace_enabled if stack_trace_enabled |
10 | 9 | c.appsec.stack_trace.max_depth = max_depth if max_depth
|
11 | 10 | c.appsec.stack_trace.max_depth_top_percent = max_depth_top_percent if max_depth_top_percent
|
12 |
| - c.appsec.stack_trace.max_collect = max_collect if max_collect |
13 | 11 | end
|
14 | 12 | end
|
15 | 13 |
|
16 |
| - let(:id) { 'b7e2370c-5d7e-4d32-990b-8812abf36588' } |
17 | 14 | # "/app/spec/support/thread_backtrace_helpers.rb:12:in `block in locations_inside_nested_blocks'",
|
18 | 15 | # "/app/spec/support/thread_backtrace_helpers.rb:14:in `block (2 levels) in locations_inside_nested_blocks'",
|
19 | 16 | # "/app/spec/support/thread_backtrace_helpers.rb:16:in `block (3 levels) in locations_inside_nested_blocks'",
|
20 | 17 | # "/app/spec/support/thread_backtrace_helpers.rb:16:in `block (4 levels) in locations_inside_nested_blocks'",
|
21 | 18 | # "/app/spec/support/thread_backtrace_helpers.rb:16:in `block (5 levels) in locations_inside_nested_blocks'",
|
22 |
| - let(:stack_trace) { ThreadBacktraceHelper.locations_inside_nested_blocks } |
23 |
| - let(:message) { 'This is a test message' } |
| 19 | + let(:frames) { ThreadBacktraceHelper.locations_inside_nested_blocks } |
24 | 20 |
|
25 | 21 | # This should use default values
|
26 |
| - let(:stack_trace_enabled) { nil } |
27 | 22 | let(:max_depth) { nil }
|
28 | 23 | let(:max_depth_top_percent) { nil }
|
29 |
| - let(:max_collect) { nil } |
30 | 24 |
|
31 | 25 | describe '::new' do
|
32 | 26 | context 'with default values' do
|
33 | 27 | it 'creates a stack trace with default values' do
|
34 |
| - expect(dd_stack_trace.id).to eq(id) |
35 |
| - expect(dd_stack_trace.id.encoding).to eq(Encoding::UTF_8) |
36 |
| - expect(dd_stack_trace.message).to eq(message) |
37 |
| - expect(dd_stack_trace.message.encoding).to eq(Encoding::UTF_8) |
38 |
| - expect(dd_stack_trace.frames.size).to eq(5) |
| 28 | + expect(collection.count).to eq(5) |
39 | 29 | end
|
40 | 30 | end
|
41 | 31 |
|
42 | 32 | context 'without values' do
|
43 |
| - let(:id) { nil } |
44 |
| - let(:stack_trace) { nil } |
45 |
| - let(:message) { nil } |
| 33 | + let(:frames) { nil } |
46 | 34 |
|
47 | 35 | it 'does not cause an error' do
|
48 |
| - expect { dd_stack_trace }.to_not raise_error |
| 36 | + expect { collection }.to_not raise_error |
49 | 37 | end
|
50 | 38 | end
|
51 | 39 |
|
52 | 40 | context 'with max_depth set to 4' do
|
53 | 41 | let(:max_depth) { 4 }
|
54 | 42 |
|
55 | 43 | it 'creates a stack trace with 4 frames, 3 top' do
|
56 |
| - expect(dd_stack_trace.frames.size).to eq(4) |
57 |
| - expect(dd_stack_trace.frames[2].text).to eq(stack_trace[2].to_s) |
58 |
| - expect(dd_stack_trace.frames[3].text).to eq(stack_trace[4].to_s) |
| 44 | + expect(collection.count).to eq(4) |
| 45 | + expect(collection[2].text).to eq(frames[2].to_s) |
| 46 | + expect(collection[3].text).to eq(frames[4].to_s) |
59 | 47 | end
|
60 | 48 |
|
61 | 49 | context 'with max_depth_top_percent set to 25' do
|
62 | 50 | let(:max_depth_top_percent) { 25 }
|
63 | 51 |
|
64 | 52 | it 'creates a stack trace with 4 frames, 1 top' do
|
65 |
| - expect(dd_stack_trace.frames.size).to eq(4) |
66 |
| - expect(dd_stack_trace.frames[0].text).to eq(stack_trace[0].to_s) |
67 |
| - expect(dd_stack_trace.frames[1].text).to eq(stack_trace[2].to_s) |
| 53 | + expect(collection.count).to eq(4) |
| 54 | + expect(collection[0].text).to eq(frames[0].to_s) |
| 55 | + expect(collection[1].text).to eq(frames[2].to_s) |
68 | 56 | end
|
69 | 57 | end
|
70 | 58 |
|
71 | 59 | context 'with max_depth_top_percent set to 100' do
|
72 | 60 | let(:max_depth_top_percent) { 100 }
|
73 | 61 |
|
74 | 62 | it 'creates a stack trace with 4 top frames' do
|
75 |
| - expect(dd_stack_trace.frames.size).to eq(4) |
76 |
| - expect(dd_stack_trace.frames[0].text).to eq(stack_trace[0].to_s) |
77 |
| - expect(dd_stack_trace.frames[3].text).to eq(stack_trace[3].to_s) |
| 63 | + expect(collection.count).to eq(4) |
| 64 | + expect(collection[0].text).to eq(frames[0].to_s) |
| 65 | + expect(collection[3].text).to eq(frames[3].to_s) |
78 | 66 | end
|
79 | 67 | end
|
80 | 68 |
|
81 | 69 | context 'with max_depth_top_percent set to 0' do
|
82 | 70 | let(:max_depth_top_percent) { 0 }
|
83 | 71 |
|
84 | 72 | it 'creates a stack trace with 4 bottom frames' do
|
85 |
| - expect(dd_stack_trace.frames.size).to eq(4) |
86 |
| - expect(dd_stack_trace.frames[0].text).to eq(stack_trace[1].to_s) |
87 |
| - expect(dd_stack_trace.frames[3].text).to eq(stack_trace[4].to_s) |
| 73 | + expect(collection.count).to eq(4) |
| 74 | + expect(collection[0].text).to eq(frames[1].to_s) |
| 75 | + expect(collection[3].text).to eq(frames[4].to_s) |
88 | 76 | end
|
89 | 77 | end
|
90 | 78 | end
|
|
96 | 84 | let(:max_depth_top_percent) { 200 / 3.0 }
|
97 | 85 |
|
98 | 86 | it 'creates a stack trace with 3 frames, 2 top' do
|
99 |
| - expect(dd_stack_trace.frames.size).to eq(3) |
100 |
| - expect(dd_stack_trace.frames[1].text).to eq(stack_trace[1].to_s) |
101 |
| - expect(dd_stack_trace.frames[2].text).to eq(stack_trace[4].to_s) |
| 87 | + expect(collection.count).to eq(3) |
| 88 | + expect(collection[1].text).to eq(frames[1].to_s) |
| 89 | + expect(collection[2].text).to eq(frames[4].to_s) |
102 | 90 | end
|
103 | 91 | end
|
104 | 92 | end
|
|
107 | 95 | let(:max_depth) { 0 }
|
108 | 96 |
|
109 | 97 | it 'does not apply any limit' do
|
110 |
| - expect(dd_stack_trace.frames.size).to eq(5) |
| 98 | + expect(collection.count).to eq(5) |
111 | 99 | end
|
112 | 100 | end
|
113 | 101 | end
|
114 | 102 |
|
115 |
| - describe '#to_h' do |
116 |
| - # To simplify the test, we set max_depth to 1 |
117 |
| - let(:max_depth) { 1 } |
118 |
| - |
119 |
| - it 'returns a hash with correct values' do |
120 |
| - expect(dd_stack_trace.to_h).to eq( |
121 |
| - { |
122 |
| - language: 'ruby', |
123 |
| - id: id, |
124 |
| - message: message, |
125 |
| - frames: [ |
126 |
| - { |
127 |
| - id: 0, |
128 |
| - text: stack_trace.first.to_s, |
129 |
| - file: stack_trace.first.absolute_path, |
130 |
| - line: stack_trace.first.lineno, |
131 |
| - function: stack_trace.first.label |
132 |
| - } |
133 |
| - ] |
134 |
| - } |
135 |
| - ) |
| 103 | + describe '#each' do |
| 104 | + it 'iterates over the frames' do |
| 105 | + expect(collection.each.to_a).to eq(collection.instance_variable_get('@frames')) |
136 | 106 | end
|
137 | 107 | end
|
138 | 108 |
|
139 | 109 | describe '#to_msgpack' do
|
140 | 110 | it 'returns a MessagePack object with correct values' do
|
141 |
| - stack_trace_msgpack = dd_stack_trace.to_msgpack |
| 111 | + stack_trace_msgpack = collection.to_msgpack |
142 | 112 |
|
143 | 113 | expect(stack_trace_msgpack).to be_a(MessagePack::Packer)
|
144 | 114 | # As message pack converts keys to string,
|
145 | 115 | # we must also convert the keys of the hash to string in this test
|
146 |
| - result = dd_stack_trace.to_h.transform_keys(&:to_s) |
147 |
| - result['frames'] = result['frames'].map { |f| f.transform_keys(&:to_s) } |
| 116 | + result = collection.map { |f| f.to_h.transform_keys(&:to_s) } |
148 | 117 |
|
149 | 118 | expect(MessagePack.unpack(stack_trace_msgpack.to_s)).to eq(result)
|
150 | 119 | end
|
151 | 120 | end
|
152 | 121 |
|
153 |
| - # add_stack_trace must be tested in integration tests, as it uses the active context |
| 122 | + # Integration tests done in rails integration test spec |
154 | 123 | end
|
155 | 124 |
|
156 | 125 | RSpec.describe Datadog::AppSec::StackTrace::Frame do
|
|
200 | 169 | end
|
201 | 170 | end
|
202 | 171 | end
|
| 172 | + |
| 173 | +RSpec.describe Datadog::AppSec::StackTrace::Representation do |
| 174 | + subject(:dd_stack_trace) { described_class.new(id, stack_trace, message: message) } |
| 175 | + |
| 176 | + let(:id) { 'stack_id' } |
| 177 | + let(:stack_trace) { Datadog::AppSec::StackTrace::Collection.new(ThreadBacktraceHelper.locations_inside_nested_blocks) } |
| 178 | + let(:message) { 'Test message' } |
| 179 | + |
| 180 | + describe '::new' do |
| 181 | + it 'creates a stack trace representation with correct values' do |
| 182 | + expect(dd_stack_trace.id).to eq(id) |
| 183 | + expect(dd_stack_trace.stack_trace).to eq(stack_trace) |
| 184 | + expect(dd_stack_trace.message).to eq(message) |
| 185 | + end |
| 186 | + end |
| 187 | + |
| 188 | + describe '#to_h' do |
| 189 | + it 'returns a hash with correct values' do |
| 190 | + expect(dd_stack_trace.to_h).to eq( |
| 191 | + { |
| 192 | + language: 'ruby', |
| 193 | + id: id, |
| 194 | + message: message, |
| 195 | + frames: stack_trace.map(&:to_h) |
| 196 | + } |
| 197 | + ) |
| 198 | + end |
| 199 | + end |
| 200 | + |
| 201 | + describe '#to_msgpack' do |
| 202 | + it 'returns a MessagePack object with correct values' do |
| 203 | + stack_trace_msgpack = dd_stack_trace.to_msgpack |
| 204 | + |
| 205 | + expect(stack_trace_msgpack).to be_a(MessagePack::Packer) |
| 206 | + # As message pack converts keys to string, |
| 207 | + # we must also convert the keys of the hash to string in this test |
| 208 | + result = dd_stack_trace.to_h.transform_keys(&:to_s) |
| 209 | + result['frames'] = result['frames'].map { |f| f.transform_keys(&:to_s) } |
| 210 | + |
| 211 | + expect(MessagePack.unpack(stack_trace_msgpack.to_s)).to eq(result) |
| 212 | + end |
| 213 | + end |
| 214 | +end |
0 commit comments