Skip to content

Commit 9035232

Browse files
committed
clean rar changes
1 parent 9e6ae65 commit 9035232

File tree

2 files changed

+143
-51
lines changed

2 files changed

+143
-51
lines changed

comp/core/remoteagent/helper/expvar.go

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,11 @@ import (
1212
pbcore "github.com/DataDog/datadog-agent/pkg/proto/pbgo/core"
1313
)
1414

15-
// ExpvarFields returns a map of all currently registered expvar key-value pairs
15+
// ExpvarFields returns a map of all currently registered expvar key-value pairs.
16+
// Each value is the JSON string returned by the expvar's String() method.
1617
func ExpvarFields() map[string]string {
1718
fields := make(map[string]string)
1819
expvar.Do(func(kv expvar.KeyValue) {
19-
var v any
20-
if err := json.Unmarshal([]byte(kv.Value.String()), &v); err == nil {
21-
if pretty, err := json.MarshalIndent(v, "", " "); err == nil {
22-
fields[kv.Key] = string(pretty)
23-
return
24-
}
25-
}
2620
fields[kv.Key] = kv.Value.String()
2721
})
2822
return fields
@@ -36,6 +30,7 @@ func DefaultStatusResponse() *pbcore.GetStatusDetailsResponse {
3630
}
3731

3832
// DefaultFlareFiles returns the standard set of flare files for a sub-process agent:
33+
// "<prefix>_status.json" with all current expvar values and "<prefix>_runtime_config_dump.json" with all config settings.
3934
func DefaultFlareFiles(settings map[string]interface{}, prefix string) map[string][]byte {
4035
files := make(map[string][]byte)
4136
if data, err := json.MarshalIndent(ExpvarData(), "", " "); err == nil {
@@ -47,16 +42,16 @@ func DefaultFlareFiles(settings map[string]interface{}, prefix string) map[strin
4742
return files
4843
}
4944

50-
// ExpvarData returns all currently registered expvar values as a structured map
45+
// ExpvarData returns all currently registered expvar values as a structured map.
46+
// Values are unmarshaled from JSON where possible; otherwise stored as raw strings.
5147
func ExpvarData() map[string]any {
5248
data := make(map[string]any)
5349
expvar.Do(func(kv expvar.KeyValue) {
5450
var v any
55-
if err := json.Unmarshal([]byte(kv.Value.String()), &v); err == nil {
56-
data[kv.Key] = v
57-
} else {
58-
data[kv.Key] = kv.Value.String()
51+
if json.Unmarshal([]byte(kv.Value.String()), &v) != nil {
52+
v = kv.Value.String()
5953
}
54+
data[kv.Key] = v
6055
})
6156
return data
6257
}

comp/trace/status/statusimpl/status_test.go

Lines changed: 135 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,61 +7,158 @@ package statusimpl
77

88
import (
99
"bytes"
10+
"strings"
1011
"testing"
12+
"time"
1113

1214
"github.com/stretchr/testify/assert"
1315
"go.uber.org/fx"
1416

15-
"github.com/DataDog/datadog-agent/comp/core/config"
16-
ipc "github.com/DataDog/datadog-agent/comp/core/ipc/def"
17-
ipcmock "github.com/DataDog/datadog-agent/comp/core/ipc/mock"
18-
17+
remoteagentregistry "github.com/DataDog/datadog-agent/comp/core/remoteagentregistry/def"
1918
"github.com/DataDog/datadog-agent/pkg/util/fxutil"
2019
)
2120

22-
func TestStatusOut(t *testing.T) {
23-
deps := fxutil.Test[dependencies](t, fx.Options(
24-
fx.Provide(func() config.Component { return config.NewMock(t) }),
25-
fx.Provide(func() ipc.HTTPClient {
26-
return ipcmock.New(t).GetClient()
27-
}),
28-
))
21+
// mockRAR is a minimal implementation of remoteagentregistry.Component for testing.
22+
type mockRAR struct {
23+
statuses []remoteagentregistry.StatusData
24+
}
2925

30-
provides := newStatus(deps)
26+
func (m *mockRAR) RegisterRemoteAgent(_ *remoteagentregistry.RegistrationData) (string, uint32, error) {
27+
return "", 0, nil
28+
}
29+
func (m *mockRAR) RefreshRemoteAgent(_ string) bool { return false }
30+
func (m *mockRAR) GetRegisteredAgents() []remoteagentregistry.RegisteredAgent { return nil }
31+
func (m *mockRAR) GetRegisteredAgentStatuses() []remoteagentregistry.StatusData { return m.statuses }
3132

32-
headerProvider := provides.StatusProvider.Provider
33+
func TestStatusWiring(t *testing.T) {
34+
// RAR is optional — wiring should succeed with no dependencies provided.
35+
deps := fxutil.Test[dependencies](t, fx.Options())
36+
provides := newStatus(deps)
37+
assert.NotNil(t, provides.StatusProvider.Provider)
38+
}
3339

40+
func TestPopulateStatus(t *testing.T) {
3441
tests := []struct {
35-
name string
36-
assertFunc func(t *testing.T)
42+
name string
43+
p statusProvider
44+
assert func(t *testing.T, result map[string]interface{})
3745
}{
38-
{"JSON", func(t *testing.T) {
39-
stats := make(map[string]interface{})
40-
headerProvider.JSON(false, stats)
46+
{
47+
name: "valid RAR data",
48+
p: statusProvider{RAR: &mockRAR{
49+
statuses: []remoteagentregistry.StatusData{
50+
{
51+
RegisteredAgent: remoteagentregistry.RegisteredAgent{Flavor: "trace_agent", LastSeen: time.Now()},
52+
// expvar values are JSON strings (as returned by expvar.Value.String())
53+
MainSection: remoteagentregistry.StatusSection{"pid": "12345", "uptime": "60"},
54+
},
55+
},
56+
}},
57+
assert: func(t *testing.T, r map[string]interface{}) {
58+
assert.Empty(t, r["error"])
59+
assert.Equal(t, float64(12345), r["pid"])
60+
},
61+
},
62+
{
63+
name: "failure reason propagates as error",
64+
p: statusProvider{RAR: &mockRAR{
65+
statuses: []remoteagentregistry.StatusData{
66+
{
67+
RegisteredAgent: remoteagentregistry.RegisteredAgent{Flavor: "trace_agent", LastSeen: time.Now()},
68+
FailureReason: "connection refused",
69+
},
70+
},
71+
}},
72+
assert: func(t *testing.T, r map[string]interface{}) {
73+
assert.Equal(t, "connection refused", r["error"])
74+
},
75+
},
76+
{
77+
name: "non-trace_agent flavor is skipped",
78+
p: statusProvider{RAR: &mockRAR{
79+
statuses: []remoteagentregistry.StatusData{
80+
{RegisteredAgent: remoteagentregistry.RegisteredAgent{Flavor: "system_probe", LastSeen: time.Now()}},
81+
},
82+
}},
83+
assert: func(t *testing.T, r map[string]interface{}) {
84+
assert.Equal(t, "not running or unreachable", r["error"])
85+
},
86+
},
87+
{
88+
name: "nil RAR reports not running",
89+
p: statusProvider{RAR: nil},
90+
assert: func(t *testing.T, r map[string]interface{}) {
91+
assert.Equal(t, "not running or unreachable", r["error"])
92+
},
93+
},
94+
}
95+
96+
for _, tt := range tests {
97+
t.Run(tt.name, func(t *testing.T) {
98+
tt.assert(t, tt.p.populateStatus())
99+
})
100+
}
101+
}
102+
103+
func TestJSON(t *testing.T) {
104+
t.Run("valid data", func(t *testing.T) {
105+
p := statusProvider{RAR: &mockRAR{
106+
statuses: []remoteagentregistry.StatusData{
107+
{
108+
RegisteredAgent: remoteagentregistry.RegisteredAgent{
109+
Flavor: "trace_agent",
110+
LastSeen: time.Now(),
111+
},
112+
MainSection: remoteagentregistry.StatusSection{"pid": "12345"},
113+
},
114+
},
115+
}}
116+
stats := make(map[string]interface{})
117+
err := p.JSON(false, stats)
118+
assert.NoError(t, err)
41119

42-
assert.NotEmpty(t, stats)
43-
}},
44-
{"Text", func(t *testing.T) {
45-
b := new(bytes.Buffer)
46-
err := headerProvider.Text(false, b)
120+
val, ok := stats["apmStats"].(map[string]interface{})
121+
assert.True(t, ok)
122+
assert.Empty(t, val["error"])
123+
})
47124

48-
assert.NoError(t, err)
125+
t.Run("error case", func(t *testing.T) {
126+
p := statusProvider{RAR: nil}
127+
stats := make(map[string]interface{})
128+
err := p.JSON(false, stats)
129+
assert.NoError(t, err)
49130

50-
assert.NotEmpty(t, b.String())
51-
}},
52-
{"HTML", func(t *testing.T) {
53-
b := new(bytes.Buffer)
54-
err := headerProvider.HTML(false, b)
131+
val, ok := stats["apmStats"].(map[string]interface{})
132+
assert.True(t, ok)
133+
assert.NotEmpty(t, val["error"])
134+
})
135+
}
55136

56-
assert.NoError(t, err)
137+
func TestText(t *testing.T) {
138+
t.Run("renders Not running when no RAR", func(t *testing.T) {
139+
p := statusProvider{RAR: nil}
140+
b := new(bytes.Buffer)
141+
err := p.Text(false, b)
142+
assert.NoError(t, err)
143+
assert.True(t, strings.Contains(b.String(), "Not running or unreachable"))
144+
})
57145

58-
assert.NotEmpty(t, b.String())
59-
}},
60-
}
146+
t.Run("renders failure reason in error output", func(t *testing.T) {
147+
p := statusProvider{RAR: &mockRAR{
148+
statuses: []remoteagentregistry.StatusData{
149+
{
150+
RegisteredAgent: remoteagentregistry.RegisteredAgent{
151+
Flavor: "trace_agent",
152+
LastSeen: time.Now(),
153+
},
154+
FailureReason: "dial tcp: connection refused",
155+
},
156+
},
157+
}}
158+
b := new(bytes.Buffer)
159+
err := p.Text(false, b)
160+
assert.NoError(t, err)
161+
assert.True(t, strings.Contains(b.String(), "dial tcp"))
162+
})
61163

62-
for _, test := range tests {
63-
t.Run(test.name, func(t *testing.T) {
64-
test.assertFunc(t)
65-
})
66-
}
67164
}

0 commit comments

Comments
 (0)