Skip to content

Commit 55356e2

Browse files
oschaafhtuch
authored andcommitted
Convert proto interface strings to enums (#98)
Signed-off-by: Otto van der Schaaf <oschaaf@we-amp.com>
1 parent 7defc6c commit 55356e2

21 files changed

Lines changed: 233 additions & 150 deletions

api/client/options.proto

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,52 @@ message RequestOptions {
1414
google.protobuf.UInt32Value request_body_size = 3 [(validate.rules).uint32 = {lte: 4194304}];
1515
}
1616

17+
// We wrap all values so we can have a unified way of option handling with respect to
18+
// defaults, merging, etc. As there's no stock concept for enumerations, we manually
19+
// define custom wrappers for them. These used to be strings, which did provide the
20+
// wrapped type.
21+
message AddressFamily {
22+
enum AddressFamilyOptions {
23+
AUTO = 0;
24+
V4 = 1;
25+
V6 = 2;
26+
}
27+
AddressFamilyOptions value = 1;
28+
}
29+
30+
message Verbosity {
31+
enum VerbosityOptions {
32+
DEFAULT = 0;
33+
INFO = 1;
34+
TRACE = 2;
35+
DEBUG = 3;
36+
WARN = 4;
37+
ERROR = 5;
38+
CRITICAL = 6;
39+
}
40+
VerbosityOptions value = 1;
41+
}
42+
43+
message OutputFormat {
44+
enum OutputFormatOptions {
45+
DEFAULT = 0;
46+
JSON = 1;
47+
HUMAN = 2;
48+
YAML = 3;
49+
}
50+
OutputFormatOptions value = 1;
51+
}
52+
53+
message SequencerIdleStrategy {
54+
enum SequencerIdleStrategyOptions {
55+
DEFAULT = 0;
56+
SPIN = 1;
57+
POLL = 2;
58+
SLEEP = 3;
59+
}
60+
SequencerIdleStrategyOptions value = 1;
61+
}
62+
1763
// TODO(oschaaf): Ultimately this will be a load test specification. The fact that it
1864
// can arrive via CLI is just a concrete detail. Change this to reflect that.
1965
message CommandLineOptions {
@@ -32,18 +78,16 @@ message CommandLineOptions {
3278
google.protobuf.StringValue concurrency =
3379
6; // [(validate.rules).string = {pattern: "^([0-9]*|auto)$"}];
3480
// See :option:`--verbosity` for details.
35-
google.protobuf.StringValue verbosity = 7
36-
[(validate.rules).string = {in: ["trace", "debug", "info", "warn", "error", "critical"]}];
81+
Verbosity verbosity = 7;
3782
// See :option:`--output-format` for details.
38-
google.protobuf.StringValue output_format = 8
39-
[(validate.rules).string = {in: ["human", "yaml", "json"]}];
83+
OutputFormat output_format = 8;
4084
// See :option:`--prefetch-connections` for details.
4185
google.protobuf.BoolValue prefetch_connections = 9;
4286
// See :option:`--burst-size` for details.
4387
google.protobuf.UInt32Value burst_size = 10 [(validate.rules).uint32 = {lte: 1000000}];
88+
4489
// See :option:`--address-family` for details.
45-
google.protobuf.StringValue address_family = 11
46-
[(validate.rules).string = {in: ["v4", "v6", "auto"]}];
90+
AddressFamily address_family = 11;
4791
oneof oneof_request_options {
4892
// See :option:`--request_options` for details.
4993
RequestOptions request_options = 12;
@@ -57,8 +101,7 @@ message CommandLineOptions {
57101
// See :option:`--max-requests-per-connection` for details.
58102
google.protobuf.UInt32Value max_requests_per_connection = 16 [(validate.rules).uint32 = {gte: 1}];
59103
// See :option:`--sequencer-idle-strategy` for details.
60-
google.protobuf.StringValue sequencer_idle_strategy = 17
61-
[(validate.rules).string = {in: ["spin", "poll", "sleep"]}];
104+
SequencerIdleStrategy sequencer_idle_strategy = 17;
62105
// See :option:`--uri` for details.
63106
google.protobuf.StringValue uri = 18; // [(validate.rules).string.uri = true];
64107
}

ci/run_coverage.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if [ "$VALIDATE_COVERAGE" == "true" ]
3232
then
3333
COVERAGE_VALUE=$(grep -Po '.*lines[.]*: \K(\d|\.)*' "${COVERAGE_SUMMARY}")
3434
# TODO(oschaaf): The target is 97.5%, so up this whenever possible in follow ups.
35-
COVERAGE_THRESHOLD=97.0
35+
COVERAGE_THRESHOLD=96.9
3636
COVERAGE_FAILED=$(echo "${COVERAGE_VALUE}<${COVERAGE_THRESHOLD}" | bc)
3737

3838
echo "HTML coverage report is in ${COVERAGE_DIR}/coverage.html"

include/nighthawk/client/benchmark_client.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class BenchmarkClient {
7070
* Sets the request method to use when sending request.
7171
* @param request_method to set.
7272
*/
73-
virtual void setRequestMethod(absl::string_view request_method) PURE;
73+
virtual void setRequestMethod(envoy::api::v2::core::RequestMethod request_method) PURE;
7474

7575
/**
7676
* Sets request header named 'key' to the specified value.

include/nighthawk/client/options.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,20 @@ class Options {
2828
virtual std::string uri() const PURE;
2929
virtual bool h2() const PURE;
3030
virtual std::string concurrency() const PURE;
31-
virtual std::string verbosity() const PURE;
32-
virtual std::string outputFormat() const PURE;
31+
virtual nighthawk::client::Verbosity::VerbosityOptions verbosity() const PURE;
32+
virtual nighthawk::client::OutputFormat::OutputFormatOptions outputFormat() const PURE;
3333
virtual bool prefetchConnections() const PURE;
3434
virtual uint32_t burstSize() const PURE;
35-
virtual std::string addressFamily() const PURE;
36-
virtual std::string requestMethod() const PURE;
35+
virtual nighthawk::client::AddressFamily::AddressFamilyOptions addressFamily() const PURE;
36+
virtual envoy::api::v2::core::RequestMethod requestMethod() const PURE;
3737
virtual std::vector<std::string> requestHeaders() const PURE;
3838
virtual uint32_t requestBodySize() const PURE;
3939
virtual const envoy::api::v2::auth::UpstreamTlsContext& tlsContext() const PURE;
4040
virtual uint32_t maxPendingRequests() const PURE;
4141
virtual uint32_t maxActiveRequests() const PURE;
4242
virtual uint32_t maxRequestsPerConnection() const PURE;
43-
virtual std::string sequencerIdleStrategy() const PURE;
43+
virtual nighthawk::client::SequencerIdleStrategy::SequencerIdleStrategyOptions
44+
sequencerIdleStrategy() const PURE;
4445

4546
/**
4647
* Converts an Options instance to an equivalent CommandLineOptions instance in terms of option

source/client/benchmark_client_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ class BenchmarkClientHttpImpl : public BenchmarkClient,
8181
bool tryStartOne(std::function<void()> caller_completion_callback) override;
8282
Envoy::Stats::Store& store() const override { return store_; }
8383

84-
void setRequestMethod(absl::string_view request_method) override {
85-
request_headers_.insertMethod().value(request_method);
84+
void setRequestMethod(envoy::api::v2::core::RequestMethod request_method) override {
85+
request_headers_.insertMethod().value(envoy::api::v2::core::RequestMethod_Name(request_method));
8686
};
8787
void setRequestHeader(absl::string_view key, absl::string_view value) override;
8888
void setRequestBodySize(uint32_t request_body_size) override {

source/client/client.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ Main::Main(Client::OptionsPtr&& options) : options_(std::move(options)) {}
4242

4343
bool Main::run() {
4444
Envoy::Thread::MutexBasicLockable log_lock;
45+
4546
auto logging_context = std::make_unique<Envoy::Logger::Context>(
46-
spdlog::level::from_str(options_->verbosity()), "[%T.%f][%t][%L] %v", log_lock);
47+
spdlog::level::from_str(
48+
nighthawk::client::Verbosity::VerbosityOptions_Name(options_->verbosity())),
49+
"[%T.%f][%t][%L] %v", log_lock);
4750
Envoy::Event::RealTimeSystem time_system; // NO_CHECK_FORMAT(real_time)
4851
ProcessImpl process(*options_, time_system);
4952
OutputCollectorFactoryImpl output_format_factory(time_system, *options_);

source/client/factories_impl.cc

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,10 @@ SequencerPtr SequencerFactoryImpl::create(Envoy::TimeSource& time_source,
6060
SequencerTarget sequencer_target = [&benchmark_client](std::function<void()> f) -> bool {
6161
return benchmark_client.tryStartOne(std::move(f));
6262
};
63-
IdleStrategy idle_strategy;
64-
std::string lowered_idle_strategy = options_.sequencerIdleStrategy();
65-
absl::AsciiStrToLower(&lowered_idle_strategy);
66-
if (lowered_idle_strategy == "spin") {
67-
idle_strategy = IdleStrategy::Spin;
68-
} else if (lowered_idle_strategy == "sleep") {
69-
idle_strategy = IdleStrategy::Sleep;
70-
} else if (lowered_idle_strategy == "poll") {
71-
idle_strategy = IdleStrategy::Poll;
72-
} else {
73-
NOT_REACHED_GCOVR_EXCL_LINE;
74-
}
75-
return std::make_unique<SequencerImpl>(platform_util_, dispatcher, time_source, start_time,
76-
std::move(rate_limiter), sequencer_target,
77-
statistic_factory.create(), statistic_factory.create(),
78-
options_.duration(), options_.timeout(), idle_strategy);
63+
return std::make_unique<SequencerImpl>(
64+
platform_util_, dispatcher, time_source, start_time, std::move(rate_limiter),
65+
sequencer_target, statistic_factory.create(), statistic_factory.create(), options_.duration(),
66+
options_.timeout(), options_.sequencerIdleStrategy());
7967
}
8068

8169
StoreFactoryImpl::StoreFactoryImpl(const Options& options) : OptionBasedFactoryImpl(options) {}
@@ -94,15 +82,16 @@ OutputCollectorFactoryImpl::OutputCollectorFactoryImpl(Envoy::TimeSource& time_s
9482
: OptionBasedFactoryImpl(options), time_source_(time_source) {}
9583

9684
OutputCollectorPtr OutputCollectorFactoryImpl::create() const {
97-
const std::string format = options_.outputFormat();
98-
if (format == "human") {
85+
switch (options_.outputFormat()) {
86+
case nighthawk::client::OutputFormat::HUMAN:
9987
return std::make_unique<Client::ConsoleOutputCollectorImpl>(time_source_, options_);
100-
} else if (format == "json") {
88+
case nighthawk::client::OutputFormat::JSON:
10189
return std::make_unique<Client::JsonOutputCollectorImpl>(time_source_, options_);
102-
} else if (format == "yaml") {
90+
case nighthawk::client::OutputFormat::YAML:
10391
return std::make_unique<Client::YamlOutputCollectorImpl>(time_source_, options_);
92+
default:
93+
NOT_REACHED_GCOVR_EXCL_LINE;
10494
}
105-
NOT_REACHED_GCOVR_EXCL_LINE;
10695
}
10796

10897
} // namespace Client

source/client/options_impl.cc

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ namespace Client {
1818
OptionsImpl::OptionsImpl(int argc, const char* const* argv) {
1919
setNonTrivialDefaults();
2020
// Override some defaults, we are in CLI-mode.
21-
verbosity_ = "info";
22-
output_format_ = "human";
21+
verbosity_ = nighthawk::client::Verbosity::INFO;
22+
output_format_ = nighthawk::client::OutputFormat::HUMAN;
2323

2424
// TODO(oschaaf): Purge the validation we perform here. Most of it should have become
2525
// redundant now that we also perform validation of the resulting proto.
@@ -99,7 +99,7 @@ OptionsImpl::OptionsImpl(int argc, const char* const* argv) {
9999
"", "address-family",
100100
fmt::format("Network addres family preference. Possible values: [auto, v4, v6]. The "
101101
"default output format is '{}'.",
102-
address_family_),
102+
nighthawk::client::AddressFamily::AddressFamilyOptions_Name(address_family_)),
103103
false, "", &address_families_allowed, cmd);
104104

105105
std::vector<std::string> request_methods = {"GET", "HEAD", "POST", "PUT",
@@ -166,18 +166,47 @@ OptionsImpl::OptionsImpl(int argc, const char* const* argv) {
166166
uri_ = uri.getValue();
167167
TCLAP_SET_IF_SPECIFIED(h2, h2_);
168168
TCLAP_SET_IF_SPECIFIED(concurrency, concurrency_);
169-
TCLAP_SET_IF_SPECIFIED(verbosity, verbosity_);
170-
TCLAP_SET_IF_SPECIFIED(output_format, output_format_);
169+
// TODO(oschaaf): is there a generic way to set these enum values?
170+
if (verbosity.isSet()) {
171+
std::string upper_cased = verbosity.getValue();
172+
absl::AsciiStrToUpper(&upper_cased);
173+
RELEASE_ASSERT(nighthawk::client::Verbosity::VerbosityOptions_Parse(upper_cased, &verbosity_),
174+
"Failed to parse verbosity");
175+
}
176+
if (output_format.isSet()) {
177+
std::string upper_cased = output_format.getValue();
178+
absl::AsciiStrToUpper(&upper_cased);
179+
RELEASE_ASSERT(
180+
nighthawk::client::OutputFormat::OutputFormatOptions_Parse(upper_cased, &output_format_),
181+
"Failed to parse output format");
182+
}
171183
TCLAP_SET_IF_SPECIFIED(prefetch_connections, prefetch_connections_);
172184
TCLAP_SET_IF_SPECIFIED(burst_size, burst_size_);
173-
TCLAP_SET_IF_SPECIFIED(address_family, address_family_);
174-
TCLAP_SET_IF_SPECIFIED(request_method, request_method_);
185+
if (address_family.isSet()) {
186+
std::string upper_cased = address_family.getValue();
187+
absl::AsciiStrToUpper(&upper_cased);
188+
RELEASE_ASSERT(
189+
nighthawk::client::AddressFamily::AddressFamilyOptions_Parse(upper_cased, &address_family_),
190+
"Failed to parse address family");
191+
}
192+
if (request_method.isSet()) {
193+
std::string upper_cased = request_method.getValue();
194+
absl::AsciiStrToUpper(&upper_cased);
195+
RELEASE_ASSERT(envoy::api::v2::core::RequestMethod_Parse(upper_cased, &request_method_),
196+
"Failed to parse request method");
197+
}
175198
TCLAP_SET_IF_SPECIFIED(request_headers, request_headers_);
176199
TCLAP_SET_IF_SPECIFIED(request_body_size, request_body_size_);
177200
TCLAP_SET_IF_SPECIFIED(max_pending_requests, max_pending_requests_);
178201
TCLAP_SET_IF_SPECIFIED(max_active_requests, max_active_requests_);
179202
TCLAP_SET_IF_SPECIFIED(max_requests_per_connection, max_requests_per_connection_);
180-
TCLAP_SET_IF_SPECIFIED(sequencer_idle_strategy, sequencer_idle_strategy_);
203+
if (sequencer_idle_strategy.isSet()) {
204+
std::string upper_cased = sequencer_idle_strategy.getValue();
205+
absl::AsciiStrToUpper(&upper_cased);
206+
RELEASE_ASSERT(nighthawk::client::SequencerIdleStrategy::SequencerIdleStrategyOptions_Parse(
207+
upper_cased, &sequencer_idle_strategy_),
208+
"Failed to parse sequencer idle strategy");
209+
}
181210

182211
// CLI-specific tests.
183212
// TODO(oschaaf): as per mergconflicts's remark, it would be nice to aggregate
@@ -247,10 +276,11 @@ OptionsImpl::OptionsImpl(const nighthawk::client::CommandLineOptions& options) {
247276
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, prefetch_connections, prefetch_connections_);
248277
burst_size_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, burst_size, burst_size_);
249278
address_family_ = PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, address_family, address_family_);
279+
250280
const auto& request_options = options.request_options();
251281
if (request_options.request_method() !=
252282
::envoy::api::v2::core::RequestMethod::METHOD_UNSPECIFIED) {
253-
request_method_ = ::envoy::api::v2::core::RequestMethod_Name(request_options.request_method());
283+
request_method_ = request_options.request_method();
254284
}
255285
request_body_size_ =
256286
PROTOBUF_GET_WRAPPED_OR_DEFAULT(request_options, request_body_size, request_body_size_);
@@ -268,14 +298,7 @@ OptionsImpl::OptionsImpl(const nighthawk::client::CommandLineOptions& options) {
268298
validate();
269299
}
270300

271-
void OptionsImpl::setNonTrivialDefaults() {
272-
concurrency_ = "1";
273-
verbosity_ = "warn";
274-
output_format_ = "json";
275-
address_family_ = "v4";
276-
request_method_ = "GET";
277-
sequencer_idle_strategy_ = "spin";
278-
}
301+
void OptionsImpl::setNonTrivialDefaults() { concurrency_ = "1"; }
279302

280303
void OptionsImpl::validate() const {
281304
// concurrency must be either 'auto' or a positive integer.
@@ -319,12 +342,10 @@ CommandLineOptionsPtr OptionsImpl::toCommandLineOptions() const {
319342
command_line_options->mutable_output_format()->set_value(outputFormat());
320343
command_line_options->mutable_prefetch_connections()->set_value(prefetchConnections());
321344
command_line_options->mutable_burst_size()->set_value(burstSize());
322-
command_line_options->mutable_address_family()->set_value(addressFamily());
345+
command_line_options->mutable_address_family()->set_value(
346+
static_cast<nighthawk::client::AddressFamily_AddressFamilyOptions>(addressFamily()));
323347
auto request_options = command_line_options->mutable_request_options();
324-
envoy::api::v2::core::RequestMethod method =
325-
envoy::api::v2::core::RequestMethod::METHOD_UNSPECIFIED;
326-
envoy::api::v2::core::RequestMethod_Parse(requestMethod(), &method);
327-
request_options->set_request_method(method);
348+
request_options->set_request_method(requestMethod());
328349
for (const auto& header : requestHeaders()) {
329350
auto header_value_option = request_options->add_request_headers();
330351
// TODO(oschaaf): expose append option in CLI? For now we just set.

source/client/options_impl.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ class OptionsImpl : public Options {
2828
std::string uri() const override { return uri_; }
2929
bool h2() const override { return h2_; }
3030
std::string concurrency() const override { return concurrency_; }
31-
std::string verbosity() const override { return verbosity_; };
32-
std::string outputFormat() const override { return output_format_; };
31+
nighthawk::client::Verbosity::VerbosityOptions verbosity() const override { return verbosity_; };
32+
nighthawk::client::OutputFormat::OutputFormatOptions outputFormat() const override {
33+
return output_format_;
34+
};
3335
bool prefetchConnections() const override { return prefetch_connections_; }
3436
uint32_t burstSize() const override { return burst_size_; }
35-
std::string addressFamily() const override { return address_family_; };
36-
std::string requestMethod() const override { return request_method_; };
37+
nighthawk::client::AddressFamily::AddressFamilyOptions addressFamily() const override {
38+
return address_family_;
39+
};
40+
envoy::api::v2::core::RequestMethod requestMethod() const override { return request_method_; };
3741
std::vector<std::string> requestHeaders() const override { return request_headers_; };
3842
uint32_t requestBodySize() const override { return request_body_size_; };
3943
const envoy::api::v2::auth::UpstreamTlsContext& tlsContext() const override {
@@ -42,7 +46,10 @@ class OptionsImpl : public Options {
4246
uint32_t maxPendingRequests() const override { return max_pending_requests_; }
4347
uint32_t maxActiveRequests() const override { return max_active_requests_; }
4448
uint32_t maxRequestsPerConnection() const override { return max_requests_per_connection_; }
45-
std::string sequencerIdleStrategy() const override { return sequencer_idle_strategy_; }
49+
nighthawk::client::SequencerIdleStrategy::SequencerIdleStrategyOptions
50+
sequencerIdleStrategy() const override {
51+
return sequencer_idle_strategy_;
52+
}
4653

4754
private:
4855
void setNonTrivialDefaults();
@@ -55,19 +62,22 @@ class OptionsImpl : public Options {
5562
std::string uri_;
5663
bool h2_{false};
5764
std::string concurrency_;
58-
std::string verbosity_;
59-
std::string output_format_;
65+
nighthawk::client::Verbosity::VerbosityOptions verbosity_{nighthawk::client::Verbosity::WARN};
66+
nighthawk::client::OutputFormat::OutputFormatOptions output_format_{
67+
nighthawk::client::OutputFormat::JSON};
6068
bool prefetch_connections_{false};
6169
uint32_t burst_size_{0};
62-
std::string address_family_;
63-
std::string request_method_;
70+
nighthawk::client::AddressFamily::AddressFamilyOptions address_family_{
71+
nighthawk::client::AddressFamily::AUTO};
72+
envoy::api::v2::core::RequestMethod request_method_{envoy::api::v2::core::RequestMethod::GET};
6473
std::vector<std::string> request_headers_;
6574
uint32_t request_body_size_{0};
6675
envoy::api::v2::auth::UpstreamTlsContext tls_context_;
6776
uint32_t max_pending_requests_{1};
6877
uint32_t max_active_requests_{largest_acceptable_uint32_option_value};
6978
uint32_t max_requests_per_connection_{largest_acceptable_uint32_option_value};
70-
std::string sequencer_idle_strategy_;
79+
nighthawk::client::SequencerIdleStrategy::SequencerIdleStrategyOptions sequencer_idle_strategy_{
80+
nighthawk::client::SequencerIdleStrategy::SPIN};
7181
};
7282

7383
} // namespace Client

0 commit comments

Comments
 (0)