Skip to content

Commit 7d125cb

Browse files
authored
add --profile-path flag (#109)
* add --profile-path flag
1 parent e18191c commit 7d125cb

File tree

3 files changed

+52
-16
lines changed

3 files changed

+52
-16
lines changed

README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,20 @@ This will run a load test with a general BSC profile.
110110

111111

112112
### Parameters and Flags
113-
- `-p, --profile`: Specifies the profile to use for the benchmark. Available profiles can be found in the profile directory. Sample usage `-p bsc.general`
114-
- `-d` or `--profile-dir`: Specifies the base directory to use which contain profiles, supporting up to one-level of subdirectories.
115-
- `-s, --shape`: Specifies the shape of the load pattern. List available shapes with `chainbench list shapes`.
116-
- `-u, --users`: Sets the number of simulated users to use for the benchmark.
117-
- `-r, --spawn-rate`: Sets the spawn rate of users per second.
118-
- `-w, --workers`: Sets the number of worker threads to use for the benchmark.
119-
- `-t, --test-time`: Sets the duration of the test to run.
113+
- `-p`, `--profile`: Specifies the profile to use for the benchmark. Available profiles can be found in the profile directory. Sample usage `-p bsc.general`
114+
- `-d`, `--profile-dir`: Specifies the base directory to use which contain profiles, supporting up to one-level of subdirectories.
115+
- `--profile-path`: Specifies the full path to the profile file to use for the benchmark. Overrides `--profile` and `--profile-dir` options.
116+
- `-s`, `--shape`: Specifies the shape of the load pattern. List available shapes with `chainbench list shapes`.
117+
- `-u`, `--users`: Sets the number of simulated users to use for the benchmark.
118+
- `-r`, `--spawn-rate`: Sets the spawn rate of users per second.
119+
- `-w`, `--workers`: Sets the number of worker threads to use for the benchmark.
120+
- `-t`, `--test-time`: Sets the duration of the test to run.
120121
- `--target`: Specifies the target blockchain node URL that the benchmark will connect to.
121122
- `--headless`: Runs the benchmark in headless mode, meaning that no graphical user interface (GUI) will be displayed during the test. This is useful for running the test on a remote server or when the GUI is not needed.
122123
- `--autoquit`: Tells the Chainbench tool to automatically quit after the test has finished. This is useful for running the benchmark in an automated environment where manual intervention is not desired.
123124
- `--help`: Displays the help message.
124125
- `--debug-trace-methods`: Enables tasks tagged with debug or trace to be executed
125-
- `-E, --exclude-tags`: Exclude tasks tagged with custom tags from the test. You may specify this option multiple times.
126+
- `-E`, `--exclude-tags`: Exclude tasks tagged with custom tags from the test. You may specify this option multiple times.
126127
- `--use-latest-blocks`: Use latest blocks for test data generation and runs a background process to update the test data with latest blocks.
127128
- `--size`: Specifies the test data size. Available values are XS, S, M, L, XL. Default is S.
128129
- `--batch`: Runs the test using batch requests. This will send multiple requests in a single batch request. The number of requests in a batch can be specified using the `--batch-size` flag. Default batch size is 10.

chainbench/main.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ def validate_profile(ctx: Context, param: Parameter, value: str) -> str:
8484
return value
8585

8686

87+
def validate_profile_path(ctx: Context, param: Parameter, value: str) -> str:
88+
if value is not None:
89+
if "profile_dir" or "profile" in ctx.params:
90+
click.echo("WARNING: Profile and Profile Directory options are ignored when --profile-path flag is used.")
91+
if "method" in ctx.params:
92+
click.echo("WARNING: Profile and Profile Directory options are ignored when method argument is used.")
93+
"""Validate profile path."""
94+
abs_profile_path = Path(value).resolve()
95+
if not abs_profile_path.exists():
96+
raise FileNotFoundError(f"Profile path not found: {abs_profile_path}")
97+
profile_exists(abs_profile_path.name.removesuffix(".py"), abs_profile_path.parent)
98+
return value
99+
100+
87101
@cli.command(
88102
help="Start a load test on the specified method. "
89103
"Alternatively, you can specify a profile to run using the --profile option instead. "
@@ -107,6 +121,14 @@ def validate_profile(ctx: Context, param: Parameter, value: str) -> str:
107121
help="Profile to run",
108122
show_default=True,
109123
)
124+
@click.option(
125+
"--profile-path",
126+
default=None,
127+
callback=validate_profile_path,
128+
type=click.Path(exists=True, dir_okay=False, file_okay=True, path_type=Path),
129+
help="Path to profile locustfile to be run. Overrides --profile and --profile-dir options.",
130+
show_default=True,
131+
)
110132
@click.option(
111133
"-s",
112134
"--shape",
@@ -193,6 +215,7 @@ def start(
193215
ctx: Context,
194216
profile: str,
195217
profile_dir: Path | None,
218+
profile_path: Path | None,
196219
shape: str | None,
197220
host: str,
198221
port: int,
@@ -243,18 +266,20 @@ def start(
243266
profile_dir = get_base_path(__file__) / "profile"
244267

245268
if method:
246-
profile_path = Path(all_methods[method])
269+
final_profile_path = Path(all_methods[method])
270+
elif profile_path:
271+
final_profile_path = profile_path
247272
elif profile:
248-
profile_path = get_profile_path(profile_dir, profile)
273+
final_profile_path = get_profile_path(profile_dir, profile)
249274
else:
250-
profile_path = profile_dir
275+
final_profile_path = profile_dir
251276

252-
if not profile_path.exists():
253-
click.echo(f"Profile path {profile_path} does not exist.")
277+
if not final_profile_path.exists():
278+
click.echo(f"Profile path {final_profile_path} does not exist.")
254279
sys.exit(1)
255280

256281
user_classes = {}
257-
for locustfile in parse_locustfile_paths([profile_path.__str__()]):
282+
for locustfile in parse_locustfile_paths([final_profile_path.__str__()]):
258283
_, _user_classes, _ = load_locustfile(locustfile)
259284
for key, value in _user_classes.items():
260285
user_classes[key] = value
@@ -273,7 +298,7 @@ def start(
273298
for test_data_type in test_data_types:
274299
click.echo(test_data_type)
275300
sys.exit(1)
276-
profile = profile_path.name
301+
profile = final_profile_path.name
277302
if not headless:
278303
enable_class_picker = True
279304

@@ -329,7 +354,7 @@ def start(
329354
custom_exclude_tags.extend(["batch", "batch_single"])
330355

331356
locust_options = LocustOptions(
332-
profile_path=profile_path,
357+
profile_path=final_profile_path,
333358
host=host,
334359
port=port,
335360
test_time=test_time,

chainbench/util/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ def get_profiles(profile_dir: Path) -> list[str]:
4242
return result
4343

4444

45+
def validate_profile_path(profile_path: Path) -> None:
46+
"""Validate profile path."""
47+
abs_profile_path = profile_path.resolve()
48+
if not profile_path.resolve().exists():
49+
raise FileNotFoundError(f"Profile file not found: {profile_path}")
50+
profiles = get_profiles(abs_profile_path.parent)
51+
if profile_path.stem.removesuffix(".py") not in profiles:
52+
raise ValueError(f"Profile file not found: {profile_path}")
53+
54+
4555
def generate_unique_dir_name() -> str:
4656
return datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
4757

0 commit comments

Comments
 (0)