Skip to content

Commit 01bcaa2

Browse files
[MM-67954] Browser agent ltbrowserapi fails on startup: missing config/config.json when deploying from GitHub release (#980)
* Moved configuration accessors to a new file structure under `config/` * Refactor logger tests to use updated config accessors path and mock node modules correctly * Moved LogSettings in browsercontroller.json to manage console and file logging from config.json * Update default logging settings in BrowserLogSettings to enable console logging and set console log level to debug * Add browser controller configuration validation and setup for agent tests - Introduced a new `setupAgentType` function to streamline the setup of agent types in tests. - Updated `TestIsBrowserAgentInstance` and `TestBrowserAgentConfigValidation` to utilize the new setup function. - Enhanced the `createLoadAgentHandler` to validate the `browsercontroller.json` configuration before creating browser agents. - Added logic in the Terraform agent configuration to upload the `browsercontroller.json` to browser agent instances, ensuring valid configurations are used during load tests. * fix test * Fix test with valid config file * Fix typo in comment * Fix typo in docs * Use t.Chdir and t.Setenv instead of os's This takes care of cleanup automatically and marks the test as not suitable for test parallelism. * Use t.TempDir instead of os.MkdirTemp The testing version takes care of cleanup automatically. --------- Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
1 parent 43de7d6 commit 01bcaa2

File tree

28 files changed

+339
-205
lines changed

28 files changed

+339
-205
lines changed

api/agent.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,25 @@ func (a *api) createLoadAgentHandler(w http.ResponseWriter, r *http.Request) {
122122
mlog.Warn("failed to detect agent_type. Going ahead assuming it's a server agent", mlog.Err(err))
123123
}
124124

125+
// Read and validate the browsercontroller.json that was uploaded by
126+
// Terraform to confirm it landed correctly and contains valid values
127+
// before proceeding with browser agent creation if it's a browser agent instance.
128+
if isBAInstance {
129+
bccfg, err := browsercontroller.ReadConfig("./config/browsercontroller.json")
130+
if err != nil {
131+
writeAgentResponse(w, http.StatusBadRequest, &client.AgentResponse{
132+
Error: fmt.Sprintf("could not read browser controller config: %s", err),
133+
})
134+
return
135+
}
136+
if err := defaults.Validate(bccfg); err != nil {
137+
writeAgentResponse(w, http.StatusBadRequest, &client.AgentResponse{
138+
Error: fmt.Sprintf("could not validate browser controller config: %s", err),
139+
})
140+
return
141+
}
142+
}
143+
125144
newC, err := NewControllerWrapper(&ltConfig, ucConfig, 0, agentId, a.metrics, isBAInstance)
126145
if err != nil {
127146
writeAgentResponse(w, http.StatusBadRequest, &client.AgentResponse{

api/agent_client_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
client "github.com/mattermost/mattermost-load-test-ng/api/client/agent"
1515
"github.com/mattermost/mattermost-load-test-ng/defaults"
16+
"github.com/mattermost/mattermost-load-test-ng/deployment"
1617
"github.com/mattermost/mattermost-load-test-ng/loadtest"
1718
"github.com/mattermost/mattermost-load-test-ng/loadtest/control"
1819
"github.com/mattermost/mattermost-load-test-ng/loadtest/control/simulcontroller"
@@ -64,6 +65,8 @@ func createAgent(t *testing.T, id, serverURL string) *client.Agent {
6465
}
6566

6667
func TestCreateAgent(t *testing.T) {
68+
setupAgentType(t, deployment.AgentTypeServer)
69+
6770
// create http.Handler
6871
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
6972

@@ -155,6 +158,8 @@ func TestCreateAgent(t *testing.T) {
155158
}
156159

157160
func TestAgentId(t *testing.T) {
161+
setupAgentType(t, deployment.AgentTypeServer)
162+
158163
// create http.Handler
159164
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
160165

@@ -168,6 +173,8 @@ func TestAgentId(t *testing.T) {
168173
}
169174

170175
func TestAgentStatus(t *testing.T) {
176+
setupAgentType(t, deployment.AgentTypeServer)
177+
171178
// create http.Handler
172179
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
173180

@@ -185,6 +192,8 @@ func TestAgentStatus(t *testing.T) {
185192
}
186193

187194
func TestAgentRunStop(t *testing.T) {
195+
setupAgentType(t, deployment.AgentTypeServer)
196+
188197
// create http.Handler
189198
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
190199

@@ -245,6 +254,8 @@ func TestAgentRunStop(t *testing.T) {
245254
}
246255

247256
func TestAgentAddRemoveUsers(t *testing.T) {
257+
setupAgentType(t, deployment.AgentTypeServer)
258+
248259
// create http.Handler
249260
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
250261

@@ -301,6 +312,8 @@ func TestAgentAddRemoveUsers(t *testing.T) {
301312
}
302313

303314
func TestAgentDestroy(t *testing.T) {
315+
setupAgentType(t, deployment.AgentTypeServer)
316+
304317
// create http.Handler
305318
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
306319

@@ -332,6 +345,8 @@ func TestAgentDestroy(t *testing.T) {
332345
}
333346

334347
func TestAgentInjectAction(t *testing.T) {
348+
setupAgentType(t, deployment.AgentTypeServer)
349+
335350
// create http.Handler
336351
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
337352

api/agent_test.go

Lines changed: 118 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,17 @@ type requestData struct {
3232
SimulControllerConfig *simulcontroller.Config `json:",omitempty"`
3333
}
3434

35+
func setupAgentType(t *testing.T, agentType string) {
36+
t.Helper()
37+
tempDir := t.TempDir()
38+
agentTypeFile := filepath.Join(tempDir, deployment.AgentTypeFileName)
39+
require.NoError(t, os.WriteFile(agentTypeFile, []byte(agentType), 0644))
40+
t.Setenv("HOME", tempDir)
41+
}
42+
3543
func TestAgentAPI(t *testing.T) {
44+
setupAgentType(t, deployment.AgentTypeServer)
45+
3646
// create http.Handler
3747
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
3848

@@ -181,6 +191,8 @@ func TestAgentAPI(t *testing.T) {
181191
}
182192

183193
func TestAgentAPIConcurrency(t *testing.T) {
194+
setupAgentType(t, deployment.AgentTypeServer)
195+
184196
// create http.Handler
185197
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
186198

@@ -303,72 +315,139 @@ func TestGetUserCredentials(t *testing.T) {
303315
}
304316

305317
func TestIsBrowserAgentInstance(t *testing.T) {
306-
// Get original home directory to restore later
307-
originalHome := os.Getenv("HOME")
308-
309318
t.Run("returns true when agent_type.txt contains browser_agent", func(t *testing.T) {
310-
// Create temporary directory to use as home
311-
tempDir, err := os.MkdirTemp("", "test_home_browser")
312-
require.NoError(t, err)
313-
defer os.RemoveAll(tempDir)
314-
315-
// Set temporary home directory
316-
os.Setenv("HOME", tempDir)
317-
defer os.Setenv("HOME", originalHome)
318-
319-
agentTypeFile := filepath.Join(tempDir, deployment.AgentTypeFileName)
320-
err = os.WriteFile(agentTypeFile, []byte(" "+deployment.AgentTypeBrowser+" \n"), 0644)
321-
require.NoError(t, err)
319+
setupAgentType(t, deployment.AgentTypeBrowser)
322320

323321
result, err := isBrowserAgentInstance()
324322
require.NoError(t, err)
325323
require.True(t, result)
326324
})
327325

328326
t.Run("returns false when agent_type.txt contains server_agent", func(t *testing.T) {
329-
tempDir, err := os.MkdirTemp("", "test_home_server")
330-
require.NoError(t, err)
331-
defer os.RemoveAll(tempDir)
332-
333-
os.Setenv("HOME", tempDir)
334-
defer os.Setenv("HOME", originalHome)
335-
336-
agentTypeFile := filepath.Join(tempDir, deployment.AgentTypeFileName)
337-
err = os.WriteFile(agentTypeFile, []byte(deployment.AgentTypeServer), 0644)
338-
require.NoError(t, err)
327+
setupAgentType(t, deployment.AgentTypeServer)
339328

340329
result, err := isBrowserAgentInstance()
341330
require.NoError(t, err)
342331
require.False(t, result)
343332
})
344333

345334
t.Run("returns false when agent_type.txt file does not exist", func(t *testing.T) {
346-
tempDir, err := os.MkdirTemp("", "test_home_missing")
347-
require.NoError(t, err)
348-
defer os.RemoveAll(tempDir)
349-
350-
os.Setenv("HOME", tempDir)
351-
defer os.Setenv("HOME", originalHome)
335+
tempDir := t.TempDir()
336+
t.Setenv("HOME", tempDir)
352337

353338
result, err := isBrowserAgentInstance()
354339
require.Error(t, err)
355340
require.False(t, result)
356341
})
357342

358343
t.Run("returns false when agent_type.txt contains unknown content", func(t *testing.T) {
359-
tempDir, err := os.MkdirTemp("", "test_home_unknown")
360-
require.NoError(t, err)
361-
defer os.RemoveAll(tempDir)
362-
363-
os.Setenv("HOME", tempDir)
364-
defer os.Setenv("HOME", originalHome)
344+
tempDir := t.TempDir()
345+
t.Setenv("HOME", tempDir)
365346

366347
agentTypeFile := filepath.Join(tempDir, deployment.AgentTypeFileName)
367-
err = os.WriteFile(agentTypeFile, []byte("unknown_agent_type"), 0644)
368-
require.NoError(t, err)
348+
require.NoError(t, os.WriteFile(agentTypeFile, []byte("unknown_agent_type"), 0644))
369349

370350
result, err := isBrowserAgentInstance()
371351
require.Error(t, err)
372352
require.False(t, result)
373353
})
374354
}
355+
356+
func TestBrowserAgentConfigValidation(t *testing.T) {
357+
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
358+
server := httptest.NewServer(handler)
359+
defer server.Close()
360+
361+
mmServer := createFakeMMServer()
362+
defer mmServer.Close()
363+
364+
e := httpexpect.New(t, server.URL+"/loadagent")
365+
366+
ltConfig := loadtest.Config{}
367+
err := defaults.Set(&ltConfig)
368+
require.NoError(t, err)
369+
ltConfig.UserControllerConfiguration.ServerVersion = control.MinSupportedVersion.String()
370+
ltConfig.ConnectionConfiguration.ServerURL = mmServer.URL
371+
ltConfig.UsersConfiguration.MaxActiveUsers = 100
372+
373+
setupBaseCfgDir := func(t *testing.T) string {
374+
t.Helper()
375+
tempDir := t.TempDir()
376+
t.Chdir(tempDir)
377+
cfgDir := filepath.Join(tempDir, "config")
378+
require.NoError(t, os.MkdirAll(cfgDir, 0755))
379+
380+
return cfgDir
381+
}
382+
383+
t.Run("fails when browsercontroller.json is missing", func(t *testing.T) {
384+
setupAgentType(t, deployment.AgentTypeBrowser)
385+
386+
// Empty config directory
387+
_ = setupBaseCfgDir(t)
388+
389+
rd := requestData{LoadTestConfig: ltConfig}
390+
e.POST("/create").WithQuery("id", "ltb0").WithJSON(rd).
391+
Expect().Status(http.StatusBadRequest).
392+
JSON().Object().ContainsKey("error")
393+
})
394+
395+
t.Run("succeeds with valid browsercontroller.json", func(t *testing.T) {
396+
setupAgentType(t, deployment.AgentTypeBrowser)
397+
398+
// Config directory with a valid browsercontroller.json
399+
cfgDir := setupBaseCfgDir(t)
400+
401+
validConfig := `{
402+
"SimulationId": "mattermostPostAndScroll",
403+
"RunInHeadless": true,
404+
"SimulationTimeoutMs": 60000,
405+
"EnabledPlugins": false,
406+
"LogSettings": {
407+
"EnableConsole": true,
408+
"ConsoleLevel": "debug",
409+
"EnableFile": true,
410+
"FileLevel": "debug",
411+
"FileLocation": "browseragent.log"
412+
}
413+
}`
414+
require.NoError(t, os.WriteFile(filepath.Join(cfgDir, "browsercontroller.json"), []byte(validConfig), 0644))
415+
416+
rd := requestData{LoadTestConfig: ltConfig}
417+
obj := e.POST("/create").WithQuery("id", "ltb1").WithJSON(rd).
418+
Expect().Status(http.StatusCreated).
419+
JSON().Object().ValueEqual("id", "ltb1")
420+
rawMsg := obj.Value("message").String().Raw()
421+
require.Equal(t, "load-test agent created", rawMsg)
422+
423+
e.POST("ltb1/stop").Expect().Status(http.StatusOK)
424+
e.DELETE("ltb1").Expect().Status(http.StatusOK)
425+
})
426+
427+
t.Run("fails with invalid browsercontroller.json values", func(t *testing.T) {
428+
setupAgentType(t, deployment.AgentTypeBrowser)
429+
430+
// Config directory with an invalid browsercontroller.json
431+
cfgDir := setupBaseCfgDir(t)
432+
433+
invalidConfig := `{
434+
"SimulationId": "",
435+
"RunInHeadless": true,
436+
"SimulationTimeoutMs": -1,
437+
"EnabledPlugins": false,
438+
"LogSettings": {
439+
"EnableConsole": true,
440+
"ConsoleLevel": "invalid_level",
441+
"EnableFile": true,
442+
"FileLevel": "debug",
443+
"FileLocation": "browseragent.log"
444+
}
445+
}`
446+
require.NoError(t, os.WriteFile(filepath.Join(cfgDir, "browsercontroller.json"), []byte(invalidConfig), 0644))
447+
448+
rd := requestData{LoadTestConfig: ltConfig}
449+
e.POST("/create").WithQuery("id", "ltb2").WithJSON(rd).
450+
Expect().Status(http.StatusBadRequest).
451+
JSON().Object().ContainsKey("error")
452+
})
453+
}

api/client_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
coordClient "github.com/mattermost/mattermost-load-test-ng/api/client/coordinator"
1515
"github.com/mattermost/mattermost-load-test-ng/coordinator"
1616
"github.com/mattermost/mattermost-load-test-ng/defaults"
17+
"github.com/mattermost/mattermost-load-test-ng/deployment"
1718
"github.com/mattermost/mattermost-load-test-ng/loadtest"
1819
"github.com/mattermost/mattermost-load-test-ng/loadtest/control"
1920
"github.com/mattermost/mattermost-load-test-ng/loadtest/control/simulcontroller"
@@ -26,6 +27,8 @@ import (
2627
const n = 8
2728

2829
func TestAgentClientConcurrency(t *testing.T) {
30+
setupAgentType(t, deployment.AgentTypeServer)
31+
2932
// create http.Handler
3033
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
3134

@@ -178,6 +181,8 @@ func TestAgentClientConcurrency(t *testing.T) {
178181
}
179182

180183
func TestCoordClientConcurrency(t *testing.T) {
184+
setupAgentType(t, deployment.AgentTypeServer)
185+
181186
// create http.Handler
182187
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
183188

api/coordinator_client_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
client "github.com/mattermost/mattermost-load-test-ng/api/client/coordinator"
1212
"github.com/mattermost/mattermost-load-test-ng/coordinator"
1313
"github.com/mattermost/mattermost-load-test-ng/defaults"
14+
"github.com/mattermost/mattermost-load-test-ng/deployment"
1415
"github.com/mattermost/mattermost-load-test-ng/loadtest"
1516
"github.com/mattermost/mattermost-load-test-ng/loadtest/control"
1617
"github.com/mattermost/mattermost-load-test-ng/logger"
@@ -38,6 +39,8 @@ func createCoordinator(t *testing.T, id, serverURL string) *client.Coordinator {
3839
}
3940

4041
func TestCreateCoordinator(t *testing.T) {
42+
setupAgentType(t, deployment.AgentTypeServer)
43+
4144
// create http.Handler
4245
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
4346

@@ -95,6 +98,7 @@ func TestCreateCoordinator(t *testing.T) {
9598
}
9699

97100
func TestCoordinatorId(t *testing.T) {
101+
setupAgentType(t, deployment.AgentTypeServer)
98102
// create http.Handler
99103
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
100104

@@ -108,6 +112,7 @@ func TestCoordinatorId(t *testing.T) {
108112
}
109113

110114
func TestCoordinatorStatus(t *testing.T) {
115+
setupAgentType(t, deployment.AgentTypeServer)
111116
// create http.Handler
112117
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
113118

@@ -125,6 +130,7 @@ func TestCoordinatorStatus(t *testing.T) {
125130
}
126131

127132
func TestCoordinatorStartStop(t *testing.T) {
133+
setupAgentType(t, deployment.AgentTypeServer)
128134
// create http.Handler
129135
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
130136

@@ -196,6 +202,7 @@ func TestCoordinatorStartStop(t *testing.T) {
196202
}
197203

198204
func TestCoordinatorDestroy(t *testing.T) {
205+
setupAgentType(t, deployment.AgentTypeServer)
199206
// create http.Handler
200207
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
201208

@@ -226,6 +233,7 @@ func TestCoordinatorDestroy(t *testing.T) {
226233
}
227234

228235
func TestCoordinatorInjectAction(t *testing.T) {
236+
setupAgentType(t, deployment.AgentTypeServer)
229237
// create http.Handler
230238
handler := SetupAPIRouter(logger.New(&logger.Settings{}), logger.New(&logger.Settings{}))
231239

0 commit comments

Comments
 (0)