Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/component/remote/http/http_test.go
4096 views
1
package http_test
2
3
import (
4
"context"
5
"fmt"
6
"net/http"
7
"net/http/httptest"
8
"sync"
9
"testing"
10
"time"
11
12
"github.com/go-kit/log/level"
13
http_component "github.com/grafana/agent/component/remote/http"
14
"github.com/grafana/agent/pkg/flow/componenttest"
15
"github.com/grafana/agent/pkg/river"
16
"github.com/grafana/agent/pkg/river/rivertypes"
17
"github.com/grafana/agent/pkg/util"
18
"github.com/grafana/dskit/backoff"
19
"github.com/stretchr/testify/require"
20
)
21
22
func Test(t *testing.T) {
23
ctx := componenttest.TestContext(t)
24
25
var handler lazyHandler
26
srv := httptest.NewServer(&handler)
27
defer srv.Close()
28
29
handler.SetHandler(func(w http.ResponseWriter, _ *http.Request) {
30
fmt.Fprintln(w, "Hello, world!")
31
})
32
33
ctrl, err := componenttest.NewControllerFromID(util.TestLogger(t), "remote.http")
34
require.NoError(t, err)
35
36
cfg := fmt.Sprintf(`
37
url = "%s"
38
method = "%s"
39
headers = {
40
"x-custom" = "value",
41
}
42
43
poll_frequency = "50ms"
44
poll_timeout = "25ms"
45
`, srv.URL, http.MethodPut)
46
var args http_component.Arguments
47
require.NoError(t, river.Unmarshal([]byte(cfg), &args))
48
49
go func() {
50
err := ctrl.Run(ctx, args)
51
require.NoError(t, err)
52
}()
53
54
require.NoError(t, ctrl.WaitRunning(time.Second), "component never started")
55
require.NoError(t, ctrl.WaitExports(time.Second), "component never exported anything")
56
57
requireExports := func(expect http_component.Exports) {
58
eventually(t, 10*time.Millisecond, 100*time.Millisecond, 5, func() error {
59
actual := ctrl.Exports().(http_component.Exports)
60
if expect != actual {
61
return fmt.Errorf("expected %#v, got %#v", expect, actual)
62
}
63
return nil
64
})
65
}
66
67
requireExports(http_component.Exports{
68
Content: rivertypes.OptionalSecret{
69
IsSecret: false,
70
Value: "Hello, world!",
71
},
72
})
73
74
// Change the content to ensure new exports get produced.
75
handler.SetHandler(func(w http.ResponseWriter, r *http.Request) {
76
fmt.Fprintln(w, "Testing!")
77
fmt.Fprintf(w, "Method: %s\n", r.Method)
78
fmt.Fprintf(w, "Header: %s\n", r.Header.Get("x-custom"))
79
})
80
require.NoError(t, ctrl.WaitExports(time.Second), "component didn't update exports")
81
requireExports(http_component.Exports{
82
Content: rivertypes.OptionalSecret{
83
IsSecret: false,
84
Value: "Testing!\nMethod: PUT\nHeader: value",
85
},
86
})
87
}
88
89
func TestUnmarshalValidation(t *testing.T) {
90
var tests = []struct {
91
testname string
92
cfg string
93
expectedError string
94
}{
95
{
96
"Missing url",
97
`
98
poll_frequency = "0"
99
`,
100
`missing required attribute "url"`,
101
},
102
{
103
"Invalid URL",
104
`
105
url = "://example.com"
106
`,
107
`parse "://example.com": missing protocol scheme`,
108
},
109
{
110
"Invalid poll_frequency",
111
`
112
url = "http://example.com"
113
poll_frequency = "0"
114
`,
115
`poll_frequency must be greater than 0`,
116
},
117
}
118
for _, tt := range tests {
119
t.Run(tt.testname, func(t *testing.T) {
120
var args http_component.Arguments
121
require.EqualError(t, river.Unmarshal([]byte(tt.cfg), &args), tt.expectedError)
122
})
123
}
124
}
125
126
func eventually(t *testing.T, min, max time.Duration, retries int, f func() error) {
127
t.Helper()
128
129
l := util.TestLogger(t)
130
131
bo := backoff.New(context.Background(), backoff.Config{
132
MinBackoff: min,
133
MaxBackoff: max,
134
MaxRetries: retries,
135
})
136
for bo.Ongoing() {
137
err := f()
138
if err == nil {
139
return
140
}
141
142
level.Error(l).Log("msg", "condition failed", "err", err)
143
bo.Wait()
144
continue
145
}
146
147
require.NoError(t, bo.Err(), "condition failed")
148
}
149
150
type lazyHandler struct {
151
mut sync.Mutex
152
inner http.HandlerFunc
153
}
154
155
func (lh *lazyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
156
lh.mut.Lock()
157
defer lh.mut.Unlock()
158
159
if lh.inner == nil {
160
http.NotFound(w, r)
161
return
162
}
163
lh.inner.ServeHTTP(w, r)
164
}
165
166
func (lh *lazyHandler) SetHandler(h http.HandlerFunc) {
167
lh.mut.Lock()
168
defer lh.mut.Unlock()
169
170
lh.inner = h
171
}
172
173