Skip to content

Commit 8e5540b

Browse files
authored
[javascript processor] Lint and add tests (#47813)
Add tests for libbeat/processors/script/javascript/javascript.go in preparation for #46988. Additionally, fix golangci-lint, run the modernizer and fix some typos. - Relates #46988
1 parent e62cd50 commit 8e5540b

File tree

7 files changed

+274
-74
lines changed

7 files changed

+274
-74
lines changed

libbeat/processors/script/javascript/beatevent_v0.go

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
package javascript
1919

2020
import (
21-
"errors"
2221
"fmt"
22+
"slices"
2323

2424
"github.com/dop251/goja"
2525

@@ -28,8 +28,8 @@ import (
2828
)
2929

3030
// IMPORTANT:
31-
// This is the user facing API within Javascript processors. Do not make
32-
// breaking changes to the JS methods. If you must make breaking changes then
31+
// This is the user-facing API within JavaScript processors. Do not make
32+
// breaking changes to the JS methods. If you must make breaking changes, then
3333
// create a new version and require the user to specify an API version in their
3434
// configuration (e.g. api_version: 2).
3535

@@ -52,48 +52,47 @@ func newBeatEventV0(s Session) (Event, error) {
5252
func newBeatEventV0Constructor(s Session) func(call goja.ConstructorCall) *goja.Object {
5353
return func(call goja.ConstructorCall) *goja.Object {
5454
if len(call.Arguments) != 1 {
55-
panic(errors.New("Event constructor requires one argument"))
55+
panic("Event constructor requires one argument")
5656
}
5757

5858
a0 := call.Argument(0).Export()
5959

6060
var fields mapstr.M
6161
switch v := a0.(type) {
62-
case map[string]interface{}:
62+
case map[string]any:
6363
fields = v
6464
case mapstr.M:
6565
fields = v
6666
default:
67-
panic(fmt.Errorf("Event constructor requires a "+
68-
"map[string]interface{} argument but got %T", a0))
67+
panic(fmt.Sprintf("Event constructor requires map[string]interface{} argument but got %T", a0))
6968
}
7069

7170
evt := &beatEventV0{
7271
vm: s.Runtime(),
7372
obj: call.This,
7473
}
7574
evt.init()
76-
evt.reset(&beat.Event{Fields: fields})
75+
_ = evt.reset(&beat.Event{Fields: fields})
7776
return nil
7877
}
7978
}
8079

8180
func (e *beatEventV0) init() {
82-
e.obj.Set("Get", e.get)
83-
e.obj.Set("Put", e.put)
84-
e.obj.Set("Rename", e.rename)
85-
e.obj.Set("Delete", e.delete)
86-
e.obj.Set("Cancel", e.cancel)
87-
e.obj.Set("Tag", e.tag)
88-
e.obj.Set("AppendTo", e.appendTo)
81+
_ = e.obj.Set("Get", e.get)
82+
_ = e.obj.Set("Put", e.put)
83+
_ = e.obj.Set("Rename", e.rename)
84+
_ = e.obj.Set("Delete", e.delete)
85+
_ = e.obj.Set("Cancel", e.cancel)
86+
_ = e.obj.Set("Tag", e.tag)
87+
_ = e.obj.Set("AppendTo", e.appendTo)
8988
}
9089

9190
// reset the event so that it can be reused to wrap another event.
9291
func (e *beatEventV0) reset(b *beat.Event) error {
9392
e.inner = b
9493
e.cancelled = false
95-
e.obj.Set("_private", e)
96-
e.obj.Set("fields", e.vm.ToValue(e.inner.Fields))
94+
_ = e.obj.Set("_private", e)
95+
_ = e.obj.Set("fields", e.vm.ToValue(e.inner.Fields))
9796
return nil
9897
}
9998

@@ -103,13 +102,13 @@ func (e *beatEventV0) Wrapped() *beat.Event {
103102
}
104103

105104
// JSObject returns the goja.Value that represents the event within the
106-
// Javascript runtime.
105+
// JavaScript runtime.
107106
func (e *beatEventV0) JSObject() goja.Value {
108107
return e.obj
109108
}
110109

111-
// get returns the specified field. If the field does not exist then null is
112-
// returned. If no field is specified then it returns entire object.
110+
// get returns the specified field. If the field does not exist, then null is
111+
// returned. If no field is specified, then it returns an entire object.
113112
//
114113
// // javascript
115114
// var dataset = evt.Get("event.dataset");
@@ -129,7 +128,7 @@ func (e *beatEventV0) get(call goja.FunctionCall) goja.Value {
129128
}
130129

131130
// put writes a value to the event. If there was a previous value assigned to
132-
// the given field then the old object is returned. It throws an exception if
131+
// the given field, then the old object is returned. It throws an exception if
133132
// you try to write a to a field where one of the intermediate values is not
134133
// an object.
135134
//
@@ -138,7 +137,7 @@ func (e *beatEventV0) get(call goja.FunctionCall) goja.Value {
138137
// evt.Put("geo.location", {"lon": -73.614830, "lat": 45.505918});
139138
func (e *beatEventV0) put(call goja.FunctionCall) goja.Value {
140139
if len(call.Arguments) != 2 {
141-
panic(errors.New("Put requires two arguments (key and value)"))
140+
panic("Put requires two arguments (key and value)")
142141
}
143142

144143
key := call.Argument(0).String()
@@ -157,7 +156,7 @@ func (e *beatEventV0) put(call goja.FunctionCall) goja.Value {
157156
// evt.Rename("src_ip", "source.ip");
158157
func (e *beatEventV0) rename(call goja.FunctionCall) goja.Value {
159158
if len(call.Arguments) != 2 {
160-
panic(errors.New("Rename requires two arguments (from and to)"))
159+
panic("Rename requires two arguments (from and to)")
161160
}
162161

163162
from := call.Argument(0).String()
@@ -181,7 +180,7 @@ func (e *beatEventV0) rename(call goja.FunctionCall) goja.Value {
181180

182181
if _, err = e.inner.PutValue(to, fromValue); err != nil {
183182
// Undo
184-
e.inner.PutValue(from, fromValue)
183+
_, _ = e.inner.PutValue(from, fromValue)
185184
return e.vm.ToValue(false)
186185
}
187186

@@ -194,7 +193,7 @@ func (e *beatEventV0) rename(call goja.FunctionCall) goja.Value {
194193
// evt.Delete("http.request.headers.authorization");
195194
func (e *beatEventV0) delete(call goja.FunctionCall) goja.Value {
196195
if len(call.Arguments) != 1 {
197-
panic(errors.New("Delete requires one argument"))
196+
panic("Delete requires one argument")
198197
}
199198

200199
key := call.Argument(0).String()
@@ -210,14 +209,14 @@ func (e *beatEventV0) IsCancelled() bool {
210209
return e.cancelled
211210
}
212211

213-
// Cancel marks the event as cancelled. When the processor returns the event
212+
// Cancel marks the event as cancelled. When the processor returns, the event
214213
// will be dropped.
215214
func (e *beatEventV0) Cancel() {
216215
e.cancelled = true
217216
}
218217

219218
// cancel marks the event as cancelled.
220-
func (e *beatEventV0) cancel(call goja.FunctionCall) goja.Value {
219+
func (e *beatEventV0) cancel(goja.FunctionCall) goja.Value {
221220
e.cancelled = true
222221
return goja.Undefined()
223222
}
@@ -229,7 +228,7 @@ func (e *beatEventV0) cancel(call goja.FunctionCall) goja.Value {
229228
// evt.Tag("_parse_failure");
230229
func (e *beatEventV0) tag(call goja.FunctionCall) goja.Value {
231230
if len(call.Arguments) != 1 {
232-
panic(errors.New("Tag requires one argument"))
231+
panic("Tag requires one argument")
233232
}
234233

235234
tag := call.Argument(0).String()
@@ -242,14 +241,14 @@ func (e *beatEventV0) tag(call goja.FunctionCall) goja.Value {
242241

243242
// appendTo is a specialized Put method that converts any existing value to
244243
// an array and appends the value if it does not already exist. If there is an
245-
// existing value that's not a string or array of strings then an exception is
244+
// existing value that's not a string or array of strings, then an exception is
246245
// thrown.
247246
//
248247
// // javascript
249248
// evt.AppendTo("error.message", "invalid file hash");
250249
func (e *beatEventV0) appendTo(call goja.FunctionCall) goja.Value {
251250
if len(call.Arguments) != 2 {
252-
panic(errors.New("AppendTo requires two arguments (field and value)"))
251+
panic("AppendTo requires two arguments (field and value)")
253252
}
254253

255254
field := call.Argument(0).String()
@@ -275,14 +274,12 @@ func appendString(m mapstr.M, field, value string, alwaysArray bool) error {
275274
m.Put(field, []string{v, value})
276275
}
277276
case []string:
278-
for _, existingTag := range v {
279-
if value == existingTag {
280-
// Duplicate
281-
return nil
282-
}
277+
if slices.Contains(v, value) {
278+
// Duplicate
279+
return nil
283280
}
284281
m.Put(field, append(v, value))
285-
case []interface{}:
282+
case []any:
286283
for _, existingTag := range v {
287284
if value == existingTag {
288285
// Duplicate

libbeat/processors/script/javascript/beatevent_v0_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ func TestBeatEventV0(t *testing.T) {
197197
// Validate that the processor's metrics exist.
198198
var found bool
199199
prefix := fmt.Sprintf("processor.javascript.%s.histogram.process_time", tc.name)
200-
reg.Do(monitoring.Full, func(name string, v interface{}) {
200+
reg.Do(monitoring.Full, func(name string, v any) {
201201
if !found && strings.HasPrefix(name, prefix) {
202202
found = true
203203
}
@@ -221,7 +221,7 @@ func BenchmarkBeatEventV0(b *testing.B) {
221221

222222
event := testEvent()
223223
b.ResetTimer()
224-
for i := 0; i < b.N; i++ {
224+
for b.Loop() {
225225
_, err := p.Run(event)
226226
if err != nil {
227227
b.Fatal(err)

libbeat/processors/script/javascript/config.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ import (
2222
"time"
2323
)
2424

25-
// Config defines the Javascript source files to use for the processor.
25+
// Config defines the JavaScript source files to use for the processor.
2626
type Config struct {
27-
Tag string `config:"tag"` // Processor ID for debug and metrics.
28-
Source string `config:"source"` // Inline script to execute.
29-
File string `config:"file"` // Source file.
30-
Files []string `config:"files"` // Multiple source files.
31-
Params map[string]interface{} `config:"params"` // Parameters to pass to script.
32-
Timeout time.Duration `config:"timeout" validate:"min=0"` // Execution timeout.
33-
TagOnException string `config:"tag_on_exception"` // Tag to add to events when an exception happens.
34-
MaxCachedSessions int `config:"max_cached_sessions" validate:"min=0"` // Max. number of cached VM sessions.
35-
OnlyCachedSessions bool `config:"only_cached_sessions"` // Only use cached VM sessions.
27+
Tag string `config:"tag"` // Processor ID for debug and metrics.
28+
Source string `config:"source"` // Inline script to execute.
29+
File string `config:"file"` // Source file.
30+
Files []string `config:"files"` // Multiple source files.
31+
Params map[string]any `config:"params"` // Parameters to pass to script.
32+
Timeout time.Duration `config:"timeout" validate:"min=0"` // Execution timeout.
33+
TagOnException string `config:"tag_on_exception"` // Tag to add to events when an exception happens.
34+
MaxCachedSessions int `config:"max_cached_sessions" validate:"min=0"` // Max. number of cached VM sessions.
35+
OnlyCachedSessions bool `config:"only_cached_sessions"` // Only use cached VM sessions.
3636
}
3737

3838
// Validate returns an error if one (and only one) option is not set.

libbeat/processors/script/javascript/javascript.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type jsProcessor struct {
4747
stats *processorStats
4848
}
4949

50-
// New constructs a new Javascript processor.
50+
// New constructs a new JavaScript processor.
5151
func New(c *config.C, log *logp.Logger) (beat.Processor, error) {
5252
conf := defaultConfig()
5353
if err := c.Unpack(&conf); err != nil {
@@ -57,7 +57,7 @@ func New(c *config.C, log *logp.Logger) (beat.Processor, error) {
5757
return NewFromConfig(conf, monitoring.Default, log)
5858
}
5959

60-
// NewFromConfig constructs a new Javascript processor from the given config
60+
// NewFromConfig constructs a new JavaScript processor from the given config
6161
// object. It loads the sources, compiles them, and validates the entry point.
6262
func NewFromConfig(c Config, reg *monitoring.Registry, logger *logp.Logger) (beat.Processor, error) {
6363
err := c.Validate()
@@ -66,12 +66,11 @@ func NewFromConfig(c Config, reg *monitoring.Registry, logger *logp.Logger) (bea
6666
}
6767

6868
var sourceFile string
69-
var sourceCode []byte
70-
69+
var sourceCode string
7170
switch {
7271
case c.Source != "":
7372
sourceFile = "inline.js"
74-
sourceCode = []byte(c.Source)
73+
sourceCode = c.Source
7574
case c.File != "":
7675
sourceFile, sourceCode, err = loadSources(c.File)
7776
case len(c.Files) > 0:
@@ -82,7 +81,7 @@ func NewFromConfig(c Config, reg *monitoring.Registry, logger *logp.Logger) (bea
8281
}
8382

8483
// Validate processor source code.
85-
prog, err := goja.Compile(sourceFile, string(sourceCode), true)
84+
prog, err := goja.Compile(sourceFile, sourceCode, true)
8685
if err != nil {
8786
return nil, err
8887
}
@@ -102,7 +101,7 @@ func NewFromConfig(c Config, reg *monitoring.Registry, logger *logp.Logger) (bea
102101
}
103102

104103
// loadSources loads javascript source from files.
105-
func loadSources(files ...string) (string, []byte, error) {
104+
func loadSources(files ...string) (string, string, error) {
106105
var sources []string
107106
buf := new(bytes.Buffer)
108107

@@ -131,7 +130,7 @@ func loadSources(files ...string) (string, []byte, error) {
131130
if hasMeta(filePath) {
132131
matches, err := filepath.Glob(filePath)
133132
if err != nil {
134-
return "", nil, err
133+
return "", "", err
135134
}
136135
sources = append(sources, matches...)
137136
} else {
@@ -140,17 +139,17 @@ func loadSources(files ...string) (string, []byte, error) {
140139
}
141140

142141
if len(sources) == 0 {
143-
return "", nil, fmt.Errorf("no sources were found in %v",
142+
return "", "", fmt.Errorf("no sources were found in %v",
144143
strings.Join(files, ", "))
145144
}
146145

147146
for _, name := range sources {
148147
if err := readFile(name); err != nil {
149-
return "", nil, err
148+
return "", "", err
150149
}
151150
}
152151

153-
return strings.Join(sources, ";"), buf.Bytes(), nil
152+
return strings.Join(sources, ";"), buf.String(), nil
154153
}
155154

156155
func annotateError(id string, err error) error {
@@ -164,7 +163,7 @@ func annotateError(id string, err error) error {
164163
}
165164

166165
// Run executes the processor on the given it event. It invokes the
167-
// process function defined in the Javascript source.
166+
// process function defined in the JavaScript source.
168167
func (p *jsProcessor) Run(event *beat.Event) (*beat.Event, error) {
169168
s := p.sessionPool.Get()
170169
defer p.sessionPool.Put(s)

0 commit comments

Comments
 (0)