1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // clang-format off
16 #include "pw_rpc/internal/log_config.h" // PW_LOG_* macros must be first.
17 // clang-format on
18
19 #include <cstring>
20
21 #include "pw_log/log.h"
22 #include "pw_rpc/fuzz/argparse.h"
23 #include "pw_rpc/fuzz/engine.h"
24 #include "pw_rpc/integration_testing.h"
25
26 namespace pw::rpc::fuzz {
27 namespace {
28
FuzzClient(int argc,char ** argv)29 int FuzzClient(int argc, char** argv) {
30 // TODO(aarongreen): Incorporate descriptions into usage message.
31 Vector<ArgParserVariant, 5> parsers{
32 // Enables additional logging.
33 BoolParser("-v", "--verbose").set_default(false),
34
35 // The number of actions to perform as part of the test. A value of 0 runs
36 // indefinitely.
37 UnsignedParser<size_t>("-n", "--num-actions").set_default(256),
38
39 // The seed value for the PRNG. A value of 0 generates a seed.
40 UnsignedParser<uint64_t>("-s", "--seed").set_default(0),
41
42 // The time, in milliseconds, that can elapse without triggering an error.
43 UnsignedParser<size_t>("-t", "--timeout").set_default(5000),
44
45 // The port use to connect to the `test_rpc_server`.
46 UnsignedParser<uint16_t>("port").set_default(48000)};
47
48 if (!ParseArgs(parsers, argc, argv).ok()) {
49 PrintUsage(parsers, argv[0]);
50 return 1;
51 }
52
53 bool verbose;
54 size_t num_actions;
55 uint64_t seed;
56 size_t timeout_ms;
57 uint16_t port;
58 if (!GetArg(parsers, "--verbose", &verbose).ok() ||
59 !GetArg(parsers, "--num-actions", &num_actions).ok() ||
60 !GetArg(parsers, "--seed", &seed).ok() ||
61 !GetArg(parsers, "--timeout", &timeout_ms).ok() ||
62 !GetArg(parsers, "port", &port).ok()) {
63 return 1;
64 }
65
66 if (!seed) {
67 seed = chrono::SystemClock::now().time_since_epoch().count();
68 }
69
70 if (auto status = integration_test::InitializeClient(port); !status.ok()) {
71 PW_LOG_ERROR("Failed to initialize client: %s", pw_StatusString(status));
72 return 1;
73 }
74
75 if (num_actions == 0) {
76 num_actions = std::numeric_limits<size_t>::max();
77 }
78
79 Fuzzer fuzzer(integration_test::client(), integration_test::kChannelId);
80 fuzzer.set_verbose(verbose);
81 fuzzer.set_timeout(std::chrono::milliseconds(timeout_ms));
82 fuzzer.Run(seed, num_actions);
83 integration_test::TerminateClient();
84 return 0;
85 }
86
87 } // namespace
88 } // namespace pw::rpc::fuzz
89
main(int argc,char ** argv)90 int main(int argc, char** argv) {
91 return pw::rpc::fuzz::FuzzClient(argc, argv);
92 }
93