Skip to content

Commit 8debf90

Browse files
authored
Enhance (#35)
* enhance bench, can use mote k6 options * fix typo * fix github action
1 parent d8f27bb commit 8debf90

File tree

5 files changed

+131
-61
lines changed

5 files changed

+131
-61
lines changed

.github/workflows/import.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,4 @@ jobs:
8484
8585
- name: run stress testing
8686
run: |
87-
python3 run.py stress run -d 3
87+
python3 run.py stress run --args='-d 3s'

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,27 @@ python3 run.py stress run --help
114114
python3 run.py stress run
115115

116116
# run all scenarios with 10 virtual users, every scenario lasts 3 seconds.
117-
python3 run.py stress run -vu 10 -d 3
117+
python3 run.py stress run --args='-u 10 -d 3s'
118118

119119
# list all stress test scenarios
120120
python3 run.py stress scenarios
121121

122122
# run go.Go1Step scenarios with 10 virtual users, every scenario lasts 3 seconds.
123-
python3 run.py stress run -vu 10 -d 3 -scenario go.Go1Step
123+
python3 run.py stress run -scenario go.Go1Step --args='-u 10 -d 3s'
124+
125+
# run go.Go1Step scenarios with special test stage.
126+
# ramping up from 0 to 10 vus in first 10 seconds, then run 10 vus in 30 seconds,
127+
# then ramping up from 10 to 50 vus in 10 seconds.
128+
python3 run.py stress run -scenario go.Go1Step --args='-s 10s:10 -s 30s:10 -s 10s:50'
129+
130+
# use csv output
131+
python3 run.py stress run -scenario go.Go1Step --args='-s 10s:10 -s 30s:10 -s 10s:50 -o csv=test.csv'
132+
```
133+
134+
for more k6 args, please refer to k6 run help.
135+
136+
```bash
137+
scripts/k6 run --help
124138
```
125139

126140
k6 config file, summary result and outputs are in `output` folder. e.g.

README_cn.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,27 @@ python3 run.py stress run --help
118118
python3 run.py stress run
119119

120120
# run all scenarios with 10 virtual users, every scenario lasts 3 seconds.
121-
python3 run.py stress run -vu 10 -d 3
121+
python3 run.py stress run --args='-u 10 -d 3s'
122122

123123
# list all stress test scenarios
124124
python3 run.py stress scenarios
125125

126126
# run go.Go1Step scenarios with 10 virtual users, every scenario lasts 3 seconds.
127-
python3 run.py stress run -vu 10 -d 3 -scenario go.Go1Step
127+
python3 run.py stress run -scenario go.Go1Step --args='-u 10 -d 3s'
128+
129+
# run go.Go1Step scenarios with special test stage.
130+
# ramping up from 0 to 10 vus in first 10 seconds, then run 10 vus in 30 seconds,
131+
# then ramping up from 10 to 50 vus in 10 seconds.
132+
python3 run.py stress run -scenario go.Go1Step --args='-s 10s:10 -s 30s:10 -s 10s:50'
133+
134+
# use csv output
135+
python3 run.py stress run -scenario go.Go1Step --args='-s 10s:10 -s 30s:10 -s 10s:50 -o csv=test.csv'
136+
```
137+
138+
更多 k6 参数,请参考。
139+
140+
```bash
141+
scripts/k6 run --help
128142
```
129143

130144
k6 config file, summary result and outputs are in `output` folder. e.g.

nebula_bench/cli.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,6 @@ def stress():
132132
default="int",
133133
help="space vid type, values should be [int, string], default: int",
134134
)
135-
@click.option("-vu", default=100, help="concurrent virtual users, default: 100")
136-
@click.option(
137-
"-d", "--duration", default=60, help="duration for every scenario, unit: second, default: 60"
138-
)
139135
@click.option("-scenario", default="all", help="run special scenario, e.g. go.Go1Step")
140136
@click.option("-c", "--controller", default="k6", help="using which test tool")
141137
@click.option(
@@ -144,8 +140,9 @@ def stress():
144140
is_flag=True,
145141
help="Dry run, just dump stress testing config file, default: False",
146142
)
143+
@click.option("--args", help="extend args for test tool")
147144
def run(
148-
folder, address, user, password, space, vid_type, scenario, controller, vu, duration, dry_run
145+
folder, address, user, password, space, vid_type, scenario, controller, args, dry_run
149146
):
150147
stress = StressFactory.gen_stress(
151148
_type=controller,
@@ -156,8 +153,7 @@ def run(
156153
space=space,
157154
vid_type=vid_type,
158155
scenarios=scenario,
159-
vu=vu,
160-
duration=duration,
156+
args = args,
161157
dry_run=dry_run,
162158
)
163159
stress.run()

nebula_bench/stress.py

Lines changed: 95 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,11 @@ def load_scenarios(scenarios):
2222

2323

2424
class Stress(object):
25+
DEFAULT_VU = 100
26+
DEFAULT_DURATION = "60s"
27+
2528
def __init__(
26-
self,
27-
folder,
28-
address,
29-
user,
30-
password,
31-
space,
32-
vid_type,
33-
scenarios,
34-
vu,
35-
duration,
36-
dry_run,
37-
**kwargs
29+
self, folder, address, user, password, space, vid_type, scenarios, args, dry_run, **kwargs
3830
):
3931
self.folder = folder or setting.DATA_FOLDER
4032
self.address = address or setting.NEBULA_ADDRESS
@@ -44,9 +36,8 @@ def __init__(
4436
self.vid_type = vid_type
4537
self.scenarios = []
4638
self.output_folder = "output"
47-
self.vu = vu
48-
self.duration = duration
4939
self.dry_run = dry_run
40+
self.args = args
5041
self.scenarios = load_scenarios(scenarios)
5142
logger.info("total stress test scenarios is {}".format(len(self.scenarios)))
5243

@@ -72,27 +63,18 @@ def gen_stress(
7263
space,
7364
vid_type,
7465
scenarios,
75-
vu,
76-
duration,
66+
args,
7767
dry_run=None,
7868
**kwargs
7969
):
8070
if _type.upper() not in cls.type_list:
8171
raise Exception("not impletment this test tool, tool is {}".format(_type))
8272

8373
clazz = cls.get_all_stress_class().get("{}Stress".format(_type.upper()), None)
74+
if args is not None:
75+
args = args.strip()
8476
return clazz(
85-
folder,
86-
address,
87-
user,
88-
password,
89-
space,
90-
vid_type,
91-
scenarios,
92-
vu,
93-
duration,
94-
dry_run,
95-
**kwargs
77+
folder, address, user, password, space, vid_type, scenarios, args, dry_run, **kwargs
9678
)
9779

9880
@classmethod
@@ -140,35 +122,99 @@ def dump_config(self, scenario):
140122
)
141123
jinja_dump(template_file, "{}/{}.js".format(self.output_folder, name), kwargs)
142124

125+
def _get_params(self):
126+
"""
127+
e.g.
128+
args:
129+
"-s 60s:0 -s 40s:30 -v"
130+
return:
131+
{
132+
"-s": ["60s:0", "40s:30"],
133+
"-v": None
134+
}
135+
"""
136+
r = {}
137+
if self.args is None:
138+
return r
139+
140+
key, value = None, None
141+
for item in self.args.split(" "):
142+
if item.startswith("-"):
143+
if key is not None and key not in r:
144+
r[key] = None
145+
key = item
146+
elif item.strip() != "":
147+
value = item
148+
if key not in r:
149+
r[key] = [value]
150+
else:
151+
r[key].append(value)
152+
153+
if key is not None and key not in r:
154+
r[key] = None
155+
return r
156+
143157
def run(self):
144158
logger.info("run stress test in k6")
145-
logger.info(
146-
"every scenario would run by {} vus and last {} secconds".format(self.vu, self.duration)
147-
)
159+
params = self._get_params()
160+
161+
# cannot use both stage and vu
162+
run_with_stage = "-s" in params or "--stage" in params
163+
vu = self.DEFAULT_VU
164+
duration = self.DEFAULT_DURATION
165+
if "-u" in params:
166+
vu = params.pop("-u")[0]
167+
if "--vus" in params:
168+
vu = params.pop("--vus")[0]
169+
if "-vu" in params:
170+
vu = params.pop("-vu")[0]
171+
172+
if "-d" in params:
173+
duration = params.pop("-d")[0]
174+
if "--duration" in params:
175+
duration = params.pop("--duration")[0]
176+
177+
logger.info("every scenario would run by {} vus and last {}".format(vu, duration))
148178
Path(self.output_folder).mkdir(exist_ok=True)
149-
for scenario in self.scenarios:
179+
if "--summary-trend-stats" not in params:
180+
params["--summary-trend-stats"] = ["min,avg,med,max,p(90),p(95),p(99)"]
181+
if setting.INFLUXDB_URL is not None and "--out" not in params and "-o" not in params:
182+
params["--out"] = ["influxdb={}".format(setting.INFLUXDB_URL)]
150183

184+
for scenario in self.scenarios:
151185
self.dump_config(scenario)
152-
# run k6
153-
command = [
154-
"scripts/k6",
155-
"run",
156-
"{}/{}.js".format(self.output_folder, scenario.name),
157-
"-u",
158-
str(self.vu),
159-
"-d",
160-
"{}s".format(self.duration),
161-
"--summary-trend-stats",
162-
"min,avg,med,max,p(90),p(95),p(99)",
163-
"--summary-export",
164-
"{}/result_{}.json".format(self.output_folder, scenario.name),
165-
]
166-
if setting.INFLUXDB_URL is not None:
167-
command.append("--out")
168-
command.append("influxdb={}".format(setting.INFLUXDB_URL))
186+
if run_with_stage:
187+
command = [
188+
"scripts/k6",
189+
"run",
190+
"{}/{}.js".format(self.output_folder, scenario.name),
191+
]
192+
else:
193+
command = [
194+
"scripts/k6",
195+
"run",
196+
"{}/{}.js".format(self.output_folder, scenario.name),
197+
"-u",
198+
str(vu),
199+
"-d",
200+
str(duration),
201+
]
202+
203+
if "--summary-export" not in params:
204+
params["--summary-export"] = [
205+
"{}/result_{}.json".format(self.output_folder, scenario.name)
206+
]
207+
208+
for param, values in params.items():
209+
if values is None:
210+
command.append(param)
211+
else:
212+
for v in values:
213+
command.append(param)
214+
command.append(v)
169215

170216
click.echo("run command as below:")
171-
click.echo(" ".join(command))
217+
click.echo(" ".join([x if "(" not in x else '"{}"'.format(x) for x in command]))
172218
if self.dry_run is not None and self.dry_run:
173219
continue
174220
run_process(command)

0 commit comments

Comments
 (0)