Skip to content

Commit 8c09e5f

Browse files
Strechclaude
andcommitted
Add specs for AppSec and InferredSpan modules
F31: 44 new examples covering: - AppSec.on_start: enabled/disabled, context creation, gateway push, fallback to active trace/span, missing security engine, error handling - AppSec.on_finish: no active context, gateway push, Event.record, metrics/telemetry export, context deactivation, deactivation on error - InferredSpan.create: managed services disabled, non-hash events, missing requestContext/stage/httpMethod, v1 span name/tags/resource_key, v2 span name/tags/resource_key, trace_digest continuation, empty domain, error handling - InferredSpan.finish: nil span, statusCode tagging, non-hash response, nil response, error handling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 416bd75 commit 8c09e5f

File tree

2 files changed

+405
-0
lines changed

2 files changed

+405
-0
lines changed

test/datadog/lambda/appsec.spec.rb

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# frozen_string_literal: true
2+
3+
require 'datadog/lambda'
4+
require 'datadog/lambda/appsec'
5+
6+
describe Datadog::Lambda::AppSec do
7+
let(:event) { {'httpMethod' => 'GET', 'path' => '/'} }
8+
let(:trace) { double('trace') }
9+
let(:span) { double('span', set_metric: nil) }
10+
let(:gateway) { double('gateway') }
11+
let(:runner) { double('runner') }
12+
let(:security_engine) { double('security_engine', new_runner: runner) }
13+
let(:context) do
14+
double(
15+
'context',
16+
state: {},
17+
export_metrics: nil,
18+
export_request_telemetry: nil,
19+
events: [],
20+
)
21+
end
22+
23+
before do
24+
allow(Datadog::AppSec::Instrumentation).to receive(:gateway).and_return(gateway)
25+
allow(gateway).to receive(:push)
26+
end
27+
28+
describe '.on_start' do
29+
context 'when appsec is disabled' do
30+
before { allow(Datadog::AppSec).to receive(:enabled?).and_return(false) }
31+
32+
it { expect(described_class.on_start(event, trace, span)).to be_nil }
33+
34+
it 'does not push gateway events' do
35+
described_class.on_start(event, trace, span)
36+
expect(gateway).not_to have_received(:push)
37+
end
38+
end
39+
40+
context 'when appsec is enabled' do
41+
before do
42+
allow(Datadog::AppSec).to receive(:enabled?).and_return(true)
43+
allow(Datadog::AppSec).to receive(:security_engine).and_return(security_engine)
44+
allow(Datadog::AppSec::Context).to receive(:activate)
45+
allow(Datadog::AppSec::Context).to receive(:new).and_return(context)
46+
end
47+
48+
it 'creates and activates an AppSec context' do
49+
described_class.on_start(event, trace, span)
50+
expect(Datadog::AppSec::Context).to have_received(:new).with(trace, span, runner)
51+
expect(Datadog::AppSec::Context).to have_received(:activate).with(context)
52+
end
53+
54+
it 'sets _dd.appsec.enabled metric on span' do
55+
described_class.on_start(event, trace, span)
56+
expect(span).to have_received(:set_metric).with(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1)
57+
end
58+
59+
it 'pushes the request event to the gateway' do
60+
described_class.on_start(event, trace, span)
61+
expect(gateway).to have_received(:push).with('aws_lambda.request.start', event)
62+
end
63+
64+
context 'when trace and span are nil' do
65+
let(:active_trace) { double('active_trace') }
66+
let(:active_span) { double('active_span', set_metric: nil) }
67+
68+
before do
69+
allow(Datadog::Tracing).to receive(:active_trace).and_return(active_trace)
70+
allow(Datadog::Tracing).to receive(:active_span).and_return(active_span)
71+
end
72+
73+
it 'falls back to active trace and span' do
74+
described_class.on_start(event, nil, nil)
75+
expect(Datadog::AppSec::Context).to have_received(:new).with(active_trace, active_span, runner)
76+
end
77+
end
78+
79+
context 'when security_engine is nil' do
80+
before { allow(Datadog::AppSec).to receive(:security_engine).and_return(nil) }
81+
82+
it 'does not activate a context' do
83+
described_class.on_start(event, trace, span)
84+
expect(Datadog::AppSec::Context).not_to have_received(:activate)
85+
end
86+
87+
it 'still pushes the gateway event' do
88+
described_class.on_start(event, trace, span)
89+
expect(gateway).to have_received(:push).with('aws_lambda.request.start', event)
90+
end
91+
end
92+
93+
context 'when an error occurs' do
94+
before { allow(Datadog::AppSec::Context).to receive(:new).and_raise(StandardError, 'boom') }
95+
96+
it 'rescues and logs' do
97+
expect { described_class.on_start(event, trace, span) }.not_to raise_error
98+
end
99+
end
100+
end
101+
end
102+
103+
describe '.on_finish' do
104+
let(:response) { {'statusCode' => 200} }
105+
106+
context 'when no active context' do
107+
before { allow(Datadog::AppSec::Context).to receive(:active).and_return(nil) }
108+
109+
it { expect(described_class.on_finish(response)).to be_nil }
110+
111+
it 'does not push gateway events' do
112+
described_class.on_finish(response)
113+
expect(gateway).not_to have_received(:push)
114+
end
115+
end
116+
117+
context 'when active context exists' do
118+
before do
119+
allow(Datadog::AppSec::Context).to receive(:active).and_return(context)
120+
allow(Datadog::AppSec::Context).to receive(:deactivate)
121+
allow(Datadog::AppSec::Event).to receive(:record)
122+
end
123+
124+
it 'pushes the response event to the gateway' do
125+
described_class.on_finish(response)
126+
expect(gateway).to have_received(:push).with('aws_lambda.response.start', response)
127+
end
128+
129+
it 'records events with the request from context state' do
130+
context.state[:request] = double('request')
131+
described_class.on_finish(response)
132+
expect(Datadog::AppSec::Event).to have_received(:record).with(
133+
context, request: context.state[:request]
134+
)
135+
end
136+
137+
it 'exports metrics and telemetry' do
138+
described_class.on_finish(response)
139+
expect(context).to have_received(:export_metrics)
140+
expect(context).to have_received(:export_request_telemetry)
141+
end
142+
143+
it 'deactivates the context' do
144+
described_class.on_finish(response)
145+
expect(Datadog::AppSec::Context).to have_received(:deactivate)
146+
end
147+
148+
context 'when an error occurs' do
149+
before { allow(gateway).to receive(:push).and_raise(StandardError, 'boom') }
150+
151+
it 'still deactivates the context' do
152+
described_class.on_finish(response)
153+
expect(Datadog::AppSec::Context).to have_received(:deactivate)
154+
end
155+
end
156+
end
157+
end
158+
end

0 commit comments

Comments
 (0)