@@ -14,6 +14,7 @@ import (
1414 "maps"
1515 "net/http"
1616 "strings"
17+ "sync"
1718 "testing"
1819
1920 dto "github.com/prometheus/client_model/go"
@@ -53,6 +54,21 @@ func newClientMock() client {
5354// Sender mock
5455type senderMock struct {
5556 sentMetrics []* agentmetric
57+
58+ // Captures from the errortracking flush path. Protected by mu
59+ // because the flush job may run concurrently with test setup and
60+ // assertions; readers MUST take the lock or use a synchronisation
61+ // barrier (e.g. wait on runner.stop().Done) that establishes
62+ // happens-before with the job's completion.
63+ //
64+ // sendLogsCallCount counts sendLogsBatch invocations; sentLogs
65+ // flattens every batch into one accumulating slice. The pair lets
66+ // tests distinguish "1 call with N records" from "N calls with 1
67+ // record each" — the latter would be a regression to per-batch
68+ // dispatch that the flattened slice alone cannot detect.
69+ sentLogsMu sync.Mutex
70+ sentLogs []Log
71+ sendLogsCallCount int
5672}
5773
5874func (s * senderMock ) startSession (_ context.Context ) * senderSession {
@@ -66,6 +82,34 @@ func (s *senderMock) sendAgentMetricPayloads(_ *senderSession, metrics []*agentm
6682}
6783func (s * senderMock ) sendEventPayload (_ * senderSession , _ * Event , _ map [string ]interface {}) {
6884}
85+ func (s * senderMock ) sendLogsBatch (_ context.Context , logs []Log ) error {
86+ s .sentLogsMu .Lock ()
87+ defer s .sentLogsMu .Unlock ()
88+ s .sendLogsCallCount ++
89+ s .sentLogs = append (s .sentLogs , logs ... )
90+ return nil
91+ }
92+
93+ // capturedLogs returns a thread-safe snapshot of the records captured
94+ // via sendLogsBatch. Tests should call this rather than reading
95+ // sentLogs directly.
96+ func (s * senderMock ) capturedLogs () []Log {
97+ s .sentLogsMu .Lock ()
98+ defer s .sentLogsMu .Unlock ()
99+ out := make ([]Log , len (s .sentLogs ))
100+ copy (out , s .sentLogs )
101+ return out
102+ }
103+
104+ // sendLogsCalls returns a thread-safe snapshot of how many times
105+ // sendLogsBatch was invoked. Pair with capturedLogs to assert
106+ // "one HTTP call per flush" (N records via 1 call, not 1 record via N
107+ // calls).
108+ func (s * senderMock ) sendLogsCalls () int {
109+ s .sentLogsMu .Lock ()
110+ defer s .sentLogsMu .Unlock ()
111+ return s .sendLogsCallCount
112+ }
69113
70114// Runner mock (TODO: use use mock.Mock)
71115type runnerMock struct {
@@ -75,7 +119,7 @@ type runnerMock struct {
75119
76120func (r * runnerMock ) run () {
77121 for _ , j := range r .jobs {
78- j .a . run ( j . profiles )
122+ j .Run ( )
79123 }
80124}
81125
@@ -1171,6 +1215,25 @@ func TestSenderConfigDDUrlWithEmptyAdditionalPoint(t *testing.T) {
11711215 assert .Equal (t , "https://instrumentation-telemetry-intake.us5.datadoghq.com./api/v2/apmtelemetry" , url )
11721216}
11731217
1218+ // TestSenderConfigLogsNoSSL verifies that logs_no_ssl: true causes buildURL to
1219+ // produce an http:// URL. Previously buildURL hardcoded "https" and ignored
1220+ // Endpoint.UseSSL(), silently dropping all telemetry in no-SSL environments.
1221+ func TestSenderConfigLogsNoSSL (t * testing.T ) {
1222+ c := `
1223+ api_key: foo
1224+ agent_telemetry:
1225+ enabled: true
1226+ logs_dd_url: "localhost:19999"
1227+ logs_no_ssl: true
1228+ `
1229+ sndr := makeSenderImpl (t , nil , c )
1230+ assert .NotNil (t , sndr )
1231+
1232+ assert .Len (t , sndr .(* senderImpl ).endpoints .Endpoints , 1 )
1233+ url := buildURL (sndr .(* senderImpl ).endpoints .Endpoints [0 ])
1234+ assert .Equal (t , "http://localhost:19999/api/v2/apmtelemetry" , url )
1235+ }
1236+
11741237func TestGetAsJSONScrub (t * testing.T ) {
11751238 var c = `
11761239 agent_telemetry:
0 commit comments