master
go 189 lines 4.85 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package httpsd
4
5 import (
6 "testing"
7
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10 )
11
12 func TestResponseParser_parse(t *testing.T) {
13 tests := map[string]struct {
14 format string
15 contentType string
16 body string
17 want []any
18 wantErr bool
19 wantErrText string
20 }{
21 "json bare array": {
22 format: formatJSON,
23 contentType: "application/json",
24 body: `[{"name":"api","url":"http://127.0.0.1"}, "http://127.0.0.2"]`,
25 want: []any{
26 map[string]any{"name": "api", "url": "http://127.0.0.1"},
27 "http://127.0.0.2",
28 },
29 },
30 "yaml bare array": {
31 format: formatYAML,
32 body: `
33 - name: api
34 url: http://127.0.0.1
35 - http://127.0.0.2
36 `,
37 want: []any{
38 map[string]any{"name": "api", "url": "http://127.0.0.1"},
39 "http://127.0.0.2",
40 },
41 },
42 "json envelope": {
43 format: formatJSON,
44 body: `{"items":[{"name":"api"}]}`,
45 want: []any{map[string]any{"name": "api"}},
46 },
47 "yaml envelope": {
48 format: formatYAML,
49 body: `
50 items:
51 - name: api
52 `,
53 want: []any{map[string]any{"name": "api"}},
54 },
55 "auto content type json": {
56 format: formatAuto,
57 contentType: "application/vnd.netdata.discovery+json; charset=utf-8",
58 body: `[{"name":"api"}]`,
59 want: []any{map[string]any{"name": "api"}},
60 },
61 "auto content type yaml": {
62 format: formatAuto,
63 contentType: "application/x-yaml",
64 body: `
65 - name: api
66 `,
67 want: []any{map[string]any{"name": "api"}},
68 },
69 "auto json first without content type": {
70 format: formatAuto,
71 body: `[{"name":"api"}]`,
72 want: []any{map[string]any{"name": "api"}},
73 },
74 "unsupported envelope": {
75 format: formatYAML,
76 body: `jobs: []`,
77 wantErr: true,
78 },
79 "unsupported item type": {
80 format: formatJSON,
81 body: `[1]`,
82 wantErr: true,
83 },
84 "malformed": {
85 format: formatAuto,
86 body: `[`,
87 wantErr: true,
88 },
89 "json trailing garbage": {
90 format: formatJSON,
91 body: `{"items":[]}garbage`,
92 wantErr: true,
93 wantErrText: "invalid character",
94 },
95 "json multiple values": {
96 format: formatJSON,
97 body: `{"items":[]} {"items":[]}`,
98 wantErr: true,
99 wantErrText: "multiple JSON values",
100 },
101 "yaml multiple documents": {
102 format: formatYAML,
103 body: `
104 items: []
105 ---
106 items: []
107 `,
108 wantErr: true,
109 wantErrText: "multiple YAML documents",
110 },
111 }
112
113 for name, tc := range tests {
114 t.Run(name, func(t *testing.T) {
115 items, err := responseParser{format: tc.format}.parse([]byte(tc.body), tc.contentType)
116
117 if tc.wantErr {
118 assert.Error(t, err)
119 if tc.wantErrText != "" {
120 assert.Contains(t, err.Error(), tc.wantErrText)
121 }
122 } else {
123 require.NoError(t, err)
124 assert.Equal(t, tc.want, items)
125 }
126 })
127 }
128 }
129
130 func TestTargetsFromItems_HashStability(t *testing.T) {
131 items1, err := parseItemsJSON([]byte(`[{"name":"api","url":"http://127.0.0.1","headers":{"b":"2","a":"1"}}]`))
132 require.NoError(t, err)
133 items2, err := parseItemsJSON([]byte(`[{"headers":{"a":"1","b":"2"},"url":"http://127.0.0.1","name":"api"}]`))
134 require.NoError(t, err)
135
136 targets1, err := targetsFromItems("source", items1)
137 require.NoError(t, err)
138 targets2, err := targetsFromItems("source", items2)
139 require.NoError(t, err)
140
141 require.Len(t, targets1, 1)
142 require.Len(t, targets2, 1)
143 assert.Equal(t, targets1[0].Hash(), targets2[0].Hash())
144 assert.Equal(t, targets1[0].TUID(), targets2[0].TUID())
145 }
146
147 func TestTargetsFromItems_ContentChangesHash(t *testing.T) {
148 items1, err := parseItemsJSON([]byte(`[{"name":"api","url":"http://127.0.0.1"}]`))
149 require.NoError(t, err)
150 items2, err := parseItemsJSON([]byte(`[{"name":"api","url":"http://127.0.0.2"}]`))
151 require.NoError(t, err)
152
153 targets1, err := targetsFromItems("source", items1)
154 require.NoError(t, err)
155 targets2, err := targetsFromItems("source", items2)
156 require.NoError(t, err)
157
158 require.Len(t, targets1, 1)
159 require.Len(t, targets2, 1)
160 assert.NotEqual(t, targets1[0].Hash(), targets2[0].Hash())
161 }
162
163 func TestTargetsFromItems_StringItem(t *testing.T) {
164 targets, err := targetsFromItems("source", []any{"http://127.0.0.1"})
165 require.NoError(t, err)
166
167 require.Len(t, targets, 1)
168 tgt := targets[0].(*target)
169 assert.Equal(t, "http://127.0.0.1", tgt.Item)
170 assert.NotEmpty(t, tgt.TUID())
171 assert.Contains(t, tgt.TUID(), "http_item-")
172 }
173
174 func TestSourceString_SanitizesURLAndIsStable(t *testing.T) {
175 cfg := Config{}
176 cfg.URL = "https://user:pass@example.com/path?token=secret#fragment"
177 cfg.Headers = map[string]string{"X-Test": "value"}
178
179 src1 := sourceString(cfg)
180 src2 := sourceString(cfg)
181
182 assert.Equal(t, src1, src2)
183 assert.Contains(t, src1, "discoverer=http,url=https://example.com/path,hash=")
184 assert.NotContains(t, src1, "user")
185 assert.NotContains(t, src1, "pass")
186 assert.NotContains(t, src1, "token")
187 assert.NotContains(t, src1, "secret")
188 assert.NotContains(t, src1, "fragment")
189 }