Skip to content

Commit 101d152

Browse files
committed
Webui: adding profile argument and display in html report
1 parent 0123c35 commit 101d152

File tree

10 files changed

+84
-1
lines changed

10 files changed

+84
-1
lines changed

Diff for: locust/argument_parser.py

+5
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,11 @@ def setup_parser_arguments(parser):
838838
dest="equal_weights",
839839
help="Use equally distributed task weights, overriding the weights specified in the locustfile.",
840840
)
841+
other_group.add_argument(
842+
"--profile",
843+
type=str,
844+
help="Set a profile to group the testruns together",
845+
)
841846

842847
user_classes_group = parser.add_argument_group("User classes")
843848
user_classes_group.add_argument(

Diff for: locust/env.py

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def __init__(
3939
available_shape_classes: dict[str, LoadTestShape] | None = None,
4040
available_user_tasks: dict[str, list[TaskSet | Callable]] | None = None,
4141
dispatcher_class: type[UsersDispatcher] = UsersDispatcher,
42+
profile: str | None = None,
4243
):
4344
self.runner: Runner | None = None
4445
"""Reference to the :class:`Runner <locust.runners.Runner>` instance"""
@@ -76,6 +77,8 @@ def __init__(
7677
"""Base URL of the target system"""
7778
self.reset_stats = reset_stats
7879
"""Determines if stats should be reset once all simulated users have been spawned"""
80+
self.profile = profile
81+
"""Profile name for the test run"""
7982
if stop_timeout is not None:
8083
self.stop_timeout = stop_timeout
8184
elif parsed_options:

Diff for: locust/html.py

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ def get_html_report(
105105
"locustfile": escape(str(environment.locustfile)),
106106
"tasks": task_data,
107107
"percentiles_to_chart": stats_module.PERCENTILES_TO_CHART,
108+
"profile": escape(str(environment.profile)),
108109
},
109110
theme=theme,
110111
)

Diff for: locust/locustfile.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from locust import HttpUser, between, task
2+
3+
import time
4+
5+
6+
class QuickstartUser(HttpUser):
7+
wait_time = between(1, 2)
8+
9+
@task
10+
def hello_world(self):
11+
self.client.get("/hello")
12+
self.client.get("/world")
13+
14+
@task(3)
15+
def view_item(self):
16+
for item_id in range(10):
17+
self.client.get(f"/item?id={item_id}", name="/item")
18+
time.sleep(1)
19+
20+
def on_start(self):
21+
self.client.post("/login", json={"username": "foo", "password": "bar"})

Diff for: locust/main.py

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def create_environment(
8989
available_user_classes=available_user_classes,
9090
available_shape_classes=available_shape_classes,
9191
available_user_tasks=available_user_tasks,
92+
profile=options.profile,
9293
)
9394

9495

Diff for: locust/test/test_load_locustfile.py

+6
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,9 @@ def test_locustfile_from_url(self):
225225
f"{os.getcwd()}/examples/basic.py",
226226
)
227227
)
228+
229+
def test_profile_flag(self):
230+
options = parse_options()
231+
self.assertEqual(None, options.profile)
232+
options = parse_options(args=["--profile", "test-profile"])
233+
self.assertEqual("test-profile", options.profile)

Diff for: locust/webui/report.html

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<script>
1818
window.templateArgs = {{ template_args|tojson }}
1919
window.theme = "{{theme}}"
20+
if (window.templateArgs.profile) {
21+
document.title = `Locust - ${window.templateArgs.profile}`
22+
}
2023
</script>
2124

2225
<script type="module" src="./src/HtmlReport.tsx"></script>

Diff for: locust/webui/src/pages/HtmlReport.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import CssBaseline from '@mui/material/CssBaseline';
33
import { ThemeProvider } from '@mui/material/styles';
44
import { combineReducers, configureStore } from '@reduxjs/toolkit';
55
import { Provider } from 'react-redux';
6+
import { useEffect } from 'react';
67

78
import { ExceptionsTable } from 'components/ExceptionsTable/ExceptionsTable';
89
import { FailuresTable } from 'components/FailuresTable/FailuresTable';
@@ -51,6 +52,12 @@ export default function HtmlReport({
5152
responseTimeStatistics,
5253
tasks,
5354
}: IReport) {
55+
useEffect(() => {
56+
document.title = window.templateArgs.profile
57+
? `Locust - ${window.templateArgs.profile}`
58+
: 'Locust';
59+
}, []);
60+
5461
return (
5562
<Provider store={reportStore}>
5663
<ThemeProvider theme={muiTheme}>
@@ -73,6 +80,12 @@ export default function HtmlReport({
7380
)}
7481
</Box>
7582
<Box sx={{ my: 2 }}>
83+
{window.templateArgs.profile && (
84+
<Box sx={{ display: 'flex', columnGap: 0.5 }}>
85+
<Typography fontWeight={600}>Profile:</Typography>
86+
<Typography>{window.templateArgs.profile}</Typography>
87+
</Box>
88+
)}
7689
<Box sx={{ display: 'flex', columnGap: 0.5 }}>
7790
<Typography fontWeight={600}>During:</Typography>
7891
<Typography>

Diff for: locust/webui/src/pages/tests/HtmlReport.test.tsx

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
import { describe, expect, test } from 'vitest';
1+
import { describe, expect, test, vi, beforeEach } from 'vitest';
22

33
import HtmlReport from 'pages/HtmlReport';
44
import { swarmReportMock } from 'test/mocks/swarmState.mock';
55
import { renderWithProvider } from 'test/testUtils';
66
import { formatLocaleString } from 'utils/date';
7+
import { IReportTemplateArgs } from 'types/swarm.types';
8+
9+
declare global {
10+
interface Window {
11+
templateArgs: IReportTemplateArgs;
12+
}
13+
}
714

815
describe('HtmlReport', () => {
16+
beforeEach(() => {
17+
// Reset window.templateArgs before each test
18+
window.templateArgs = {} as IReportTemplateArgs;
19+
document.title = '';
20+
});
21+
922
test('renders a report', () => {
1023
const { getByRole, getByText } = renderWithProvider(<HtmlReport {...swarmReportMock} />);
1124

@@ -19,6 +32,21 @@ describe('HtmlReport', () => {
1932
expect(getByText(swarmReportMock.host)).toBeTruthy();
2033
});
2134

35+
test('profile is not rendered when it is not present', () => {
36+
const { queryByText } = renderWithProvider(<HtmlReport {...swarmReportMock} />);
37+
38+
expect(queryByText('Profile:')).toBeNull();
39+
});
40+
41+
test('profile is rendered when it is present', () => {
42+
window.templateArgs.profile = 'test-profile';
43+
const { getByText } = renderWithProvider(<HtmlReport {...swarmReportMock} />);
44+
45+
expect(getByText('Profile:')).toBeTruthy();
46+
expect(getByText('test-profile')).toBeTruthy();
47+
expect(document.title).toBe('Locust - test-profile');
48+
});
49+
2250
test('formats the start and end time as expected', () => {
2351
const { getByText } = renderWithProvider(<HtmlReport {...swarmReportMock} />);
2452

Diff for: locust/webui/src/types/swarm.types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface ISwarmState {
6464
users: { [key: string]: ISwarmUser };
6565
version: string;
6666
workerCount: number;
67+
profile?: string;
6768
}
6869

6970
export interface IReport {
@@ -86,6 +87,7 @@ export interface IReportTemplateArgs extends Omit<IReport, 'charts'> {
8687
isReport?: boolean;
8788
percentilesToChart: number[];
8889
percentilesToStatistics: number[];
90+
profile?: string;
8991
}
9092

9193
export interface ISwarmFormInput

0 commit comments

Comments
 (0)