Skip to content

Commit 5586de9

Browse files
Working on T-DB.
1 parent c2dfb42 commit 5586de9

File tree

4 files changed

+106
-57
lines changed

4 files changed

+106
-57
lines changed

test/test_data_blaster/README.md

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,75 @@
11
# Test Data Blaster
22

3-
The Test Data Blaster (T-DB) applications are:
4-
- Data sender / receiver (DSR)
5-
- Statistics and logging monitor
3+
The Test Data Blaster (T-DB) is an application suite that performs distributed testing, both TCP and UDP (currently the UDP portion is not implemented). There are multiple binaries in the suite:
4+
- Data sender / receiver (DSR), a TCP and (future) UDP version
5+
- Statistics and logging monitor, a C++ and (future) Python version
66

7-
There are two varieties of the DSR (data sender / receiver), one for TCP/IP and one for UDP/IP. Having separate code bases (and executables) simplifies the command line parameters as well as the internal logic. There is common code, some already factored out in the `shared_test` directory, with additional common code factored out in this (`test_data_blaster`) directory.
7+
A single instance of the monitor shows statistics from the DSR instances. The monitor is also responsible for shutting down the DSRs. Multiple DSR instances are typically running at the same time. Each TCP DSR instance can be configured for multiple TCP connectors and multiple TCP acceptors at the same time. Each (future) UDP DSR can be configured for multiple senders and receivers at the same time.
88

9-
The monitor application is the same for both the TCP/IP DSR and the UDP/IP DSR, and the same monitor instance can be run to monitor TCP and UDP DSR testing at the same time (to handle this use case, a protocol flag is part of the monitor message definition).
9+
The same monitor instance can be run for both TCP and UDP (the messages sent to the monitor from the DSRs specify whether the test data is being sent over TCP or UDP).
1010

11-
While the data sender and receiver apps are written in C++, the monitor app can be written in any language (and both a C++ and Python version is expected, with the Python version having a simple GUI display). The monitor message definition is text only, so binary endianness is not a factor.
11+
While the DSRs are written in C++, the monitor app can be written in any language (and both a C++ and Python version is expected, with the Python version having a simple GUI display). The monitor message definition is text only, so binary endianness is not a factor.
1212

13-
## Monitor Process
13+
## Usage
1414

15-
The T-DB Monitor is run as a server (only). It accepts TCP connections on one port, each connection corresponding to one instance of either a TCP T-DB sender / receiver or a UDP T-DB sender / receiver.
15+
(Fill in command line usage here - note that typically the monitor is started first.)
1616

17-
There are no "begin" or "end" data messages, a new incoming TCP connection is the indication that a new DSR instance has started, and the end of the TCP connection is the indication that the DSR instance has ended.
17+
(Fill in details about expected output.)
18+
19+
(Fill in details about how to trigger shutdown through the monitor.)
20+
21+
## Building Test Data Blaster
22+
23+
All of the C++ components can be built using CMake.
24+
25+
(Fill in details, including single build instructions in Linux, and future Python build instructions.)
26+
27+
## Internals and Design
28+
29+
Having separate code bases (and executables) for the TCP and UDP DSRs simplifies the command line parameters as well as the internal logic. There is no specific technical reason why the DSR couldn't handle both TCP and UDP, but the DSR command line is complicated enough as is
30+
31+
There is (obviously) common code between all of the T-DB C++ components, some from the `shared_test` directory (i.e. shared with the Chops Net IP unit tests), and some factored out in this (`test_data_blaster`) directory.
32+
33+
### Monitor Process
34+
35+
The T-DB Monitor is run as a server (only). It accepts TCP connections on one port, each connection corresponding to one instance of either a TCP DSR or a UDP DSR.
36+
37+
There are no "begin" or "end" data messages that the monitor has to process, a new incoming TCP connection is the indication that a new DSR instance has started, and the end of the TCP connection is the indication that the DSR instance has ended.
1838

1939
The DSR will not send a monitor message for every test message sent between DSR instances. A "modulo" command line parameter specifies how often a monitor message will be sent (for each test data set). (A modulo of 1 would generate one monitor message per test data set message.)
2040

2141
The monitor process will notify all DSR processes to shutdown by sending a shutdown message through each monitor connection. The monitor process will have a user initiated way to send the shutdown messages and end the monitor process.
2242

23-
### Monitor Message Definition
43+
#### Monitor Message Definition
2444

25-
Each message to the Monitor has the following fields:
45+
Each message from the DSRs to the monitor has the following fields:
2646
- DSR name
2747
- DSR protocol, either "tcp" or "udp"
2848
- Remote endpoint (host, port)
2949
- Data direction, either "incoming" or "outgoing"
3050
- Current message number
31-
- Total messages expected or to be sent
32-
-- with previous field this makes either "100th message out of 10,000 expected / sent" displays possible
51+
- Total messages expected to be sent (or 0 if incoming messages -- with the previous field this makes "100th message out of 10,000 to be sent" displays possible)
3352
- Current message size
34-
- Current message prefix
35-
- Current message body character
36-
- Outgoing queue size (only meaningful for outgoing data)
53+
- Current message beginning (first 15 characters)
54+
- Outgoing queue size (will always be 0 for incoming data, and 0 for outgoing data if the receiving end is keeping up)
3755

38-
Each of the fields is a text string, and the full message is delimited by
56+
Each of the fields is a text string, and the full message is delimited by (fill in details).
3957

4058
TODO - define a format that makes Python deserialization easy. Specifically, are each of the text fields nul character terminated, or is there a length prefix? Do we want name / value pairs instead of value only fields? Is the end of the message delimited by a LF (line feed) character or CR / LF (carriage return / line feed)?
4159

60+
The shutdown message is the only message sent from the monitor to the DSRs and has the following fields:
61+
62+
(Fill in details.)
4263

43-
## TCP Data Sender Receiver
64+
### TCP Data Sender Receiver
4465

4566
Each DSR instance can start multiple TCP connectors and multiple TCP acceptors as provided via the command line arguments.
4667

4768
If the DSR instance is configured to send messages (send count > 0), messages are sent when a connection is made. For TCP connectors this is when the connect succeeds. For acceptors it is when each incoming connection is made. Each connection will send out the full set of test messages.
4869

49-
Degenerate configurations are possible, with infinite message loops or where connection and shutdown timing is not clear. The T-DB is meant to be run by knowledgeable users, not general developers, so no special coding is in the T-DB to protect for bad configurations.
70+
Degenerate configurations are possible, with infinite message loops or where connection and shutdown timing is not clear. No special coding is in the T-DB to protect for bad configurations.
5071

51-
The internal data messages uses the binary marshalled message format from the `shared_test` facilities (see `msg_handling.hpp` for specific code). The monitor messages are text based messages with all fields in a string format easy to unmarshall for Python applications.
72+
The DSR internal data messages uses the binary marshalled message format from the `shared_test` facilities (see `msg_handling.hpp` for specific code). The monitor messages are text based messages with all fields in a string format easy to unmarshall for Python applications.
5273

5374
The general logic flow:
5475
- Process command line arguments

test/test_data_blaster/monitor_msg_handling.hpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
#include <cstddef> // std::size_t
2222
#include <future>
2323
#include <utility> // std::move
24-
#include <optional>
2524
#include <type_traits> // std::is_same
2625

2726
#include "net_ip/net_ip.hpp"
2827
#include "net_ip/net_entity.hpp"
28+
#include "net_ip_component/error_delivery.hpp"
2929

3030
#include "asio/ip/basic_endpoint.hpp"
3131

@@ -35,16 +35,18 @@ namespace test {
3535
enum msg_direction { incoming, outgoing };
3636

3737
struct monitor_msg_data {
38+
39+
static constexpr max_msg_data_to_capture = 15;
40+
3841
std::string m_dsr_name;
3942
std::string m_protocol; // "tcp" or "udp"
4043
std::string m_remote_host;
4144
std::string m_remote_port;
4245
msg_direction m_direction;
4346
std::size_t m_curr_msg_num;
4447
std::size_t m_curr_msg_size;
45-
std::string m_curr_prefix;
46-
char m_curr_body_char;
47-
std::size_t m_total_msgs_to_send; // 0 if incoming direction, since total not known
48+
std::string m_curr_msg_beginning; // up to max_msg_data_to_capture chars
49+
std::size_t m_total_msgs_to_send; // 0 if direction is incoming, since total not known in advance
4850
std::size_t m_outgoing_queue_size;
4951

5052
template <typename AsioIpProtocol>
@@ -53,8 +55,7 @@ struct monitor_msg_data {
5355
msg_direction direction,
5456
std::size_t curr_msg_num,
5557
std::size_t curr_msg_size,
56-
const std::string& curr_prefix,
57-
char curr_body_char,
58+
const std::string& curr_msg_beginning,
5859
std::size_t total_msgs_to_send,
5960
std::size_t outgoing_queue_size) :
6061
m_dsr_name(dsr_name),
@@ -64,8 +65,7 @@ struct monitor_msg_data {
6465
m_direction(direction),
6566
m_curr_msg_num(curr_msg_num),
6667
m_curr_msg_size(curr_msg_size),
67-
m_curr_prefix(curr_prefix),
68-
m_curr_body_char(curr_body_char),
68+
m_curr_msg_beginning(curr_msg_beginning),
6969
m_total_msgs_to_send(total_msgs_to_send),
7070
m_outgoing_queue_size(outgoing_queue_size)
7171
{
@@ -75,24 +75,27 @@ struct monitor_msg_data {
7575
m_protocol = "udp";
7676
}
7777
}
78-
79-
// more constructors to be added
8078
};
8179

8280
struct shutdown_msg {
8381
// to be filled in
8482
};
8583

8684

87-
// shutdown message from monitor process will cause promise to be set, which is signal to DSR to
88-
// shutdown
85+
// shutdown message from monitor process will set promise, which causes future to pop, which
86+
// tells DSR to shutdown
8987
class monitor_connector {
9088
public:
9189

92-
monitor_connector(chops::net::net_ip& net_ip, std::string_view monitor_port, std::string_view monitor_host,
93-
std::promise<void> prom) : // fill in initializer list, promise must use std::move
90+
monitor_connector(chops::net::net_ip& net_ip,
91+
std::string_view monitor_port, std::string_view monitor_host,
92+
std::promise<void> prom,
93+
chops::net::err_wait_q& err_wq) : m_monitor(), m_io_output()
94+
// fill in initializer list, promise must use std::move
9495

9596
{
97+
// make_tcp_connector, start, provide state chg func obj that does start_io,
98+
// providing msg handler for shutdown, make_err_func_with_wait_queue for error display
9699
}
97100
void send_monitor_msg (const monitor_msg_data& msg_data) const {
98101

test/test_data_blaster/tcp_dsr.cpp

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,57 @@
3131
#include "net_ip/net_entity.hpp"
3232

3333
#include "net_ip_component/worker.hpp"
34-
#include "net_ip_component/io_output_delivery.hpp"
3534
#include "net_ip_component/output_queue_stats.hpp"
3635
#include "net_ip_component/error_delivery.hpp"
3736

3837
#include "shared_test/msg_handling.hpp"
3938
#include "marshall/shared_buffer.hpp"
4039

4140
#include "test_data_blaster/tcp_dsr_args.hpp"
41+
#include "test_data_blaster/monitor_msg_handling.hpp"
42+
43+
const std::string_view msg_prefix { "Tasty testing!" };
44+
45+
std::size_t send_msgs_func (chops::net::io_output io_out, char body_char,
46+
int send_count, std::chrono::milliseconds delay) {
47+
48+
auto msgs = chops::test::make_msg_vec (chops::test::make_variable_len_msg, msg_prefix,
49+
body_char, send_count);
50+
for (const auto& m : msgs) {
51+
if (!io_out.is_valid()) {
52+
break;
53+
}
54+
io_out.send(m);
55+
--send_count;
56+
std::this_thread::sleep_for(delay);
57+
}
58+
return send_count; // 0 unless stopped early
59+
}
60+
4261

4362
struct state_chg {
63+
int m_send_count;
64+
char m_body_char;
65+
std::chrono::milliseconds m_delay;
66+
bool m_reply;
67+
68+
state_chg(int send_count, char body_char, std::chrono::milliseconds delay) :
69+
m_send_count(send_count), m_body_char(body_char), m_delay(delay) { }
70+
71+
void operator() (chops::net::tcp_io_interface io_intf, std::size_t, bool starting) {
72+
if (starting) {
73+
74+
}
75+
}
4476

4577
};
4678

4779

4880
int main (int argc, char* argv[]) {
4981

5082
auto parms = chops::test::tcp_dsr_args_parse_command_line(argc, argv);
51-
chops::test::vec_buf msgs{};
52-
int delay{0};
53-
if (parms.m_sending_parms) {
54-
const auto& t = *parms.m_sending_parms;
55-
delay = t.m_delay;
56-
msgs = chops::test::make_msg_vec (chops::test::make_variable_len_msg, t.m_prefix, t.m_body_char, t.m_send_count);
57-
}
83+
84+
char body_char { 'a' };
5885

5986
chops::net::worker wk;
6087
wk.start();
@@ -67,11 +94,16 @@ int main (int argc, char* argv[]) {
6794
std::promise<void> shutdown_prom;
6895
auto shutdown_fut = shutdown_prom.get_future();
6996

70-
chops::test::monitor_connector mon(nip, parms.m_monitor.m_port, parms.m_monitor.m_host, std::move(shutdown_prom));
97+
chops::test::monitor_connector mon(nip, parms.m_monitor.m_port, parms.m_monitor.m_host,
98+
std::move(shutdown_prom), err_wq);
7199

72100
for (const auto& s : parms.m_acceptors) {
73101

74102
}
103+
for (const auto& s : parms.m_connectors) {
104+
105+
}
106+
75107

76108
shutdown_fut.get();
77109
err_wq.close();

test/test_data_blaster/tcp_dsr_args.hpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,11 @@
1919
#include <string>
2020
#include <cstddef> // std::size_t
2121
#include <vector>
22-
#include <optional>
22+
#include <chrono>
2323

2424
namespace chops {
2525
namespace test {
2626

27-
constexpr int prefix_max_size {20}; // arbitrary max size - we can adjust as needed
28-
29-
struct sending_parms {
30-
int m_send_count; // num msgs to send
31-
std::string m_prefix; // prefix string, same for each message
32-
char m_body_char; // each message will be filled with this char, after the prefix
33-
int m_delay; // delay in milliseconds between messages
34-
};
35-
3627
struct connector_info {
3728
std::string m_port;
3829
std::string m_host;
@@ -41,10 +32,11 @@ struct connector_info {
4132
// command line argument data for use by TCP DSR
4233
struct tcp_dsr_args {
4334
std::string m_dsr_name; // name of this DSR instance
44-
bool m_reply; // if true, incoming messages are reflected back to sender
35+
bool m_reply; // if true, incoming messages reflected back to sender
4536
int m_modulus; // how often to send log msg to monitor, both outgoing and incoming messages
46-
std::optional<sending_parms>
47-
m_sending_parms; // if present - count, prefix, body char
37+
int m_send_count; // if 0, don't send any messages
38+
std::chrono::milliseconds
39+
m_delay;
4840
std::vector<std::string>
4941
m_acceptors; // 0 - N TCP acceptors, port for each entry
5042
std::vector<connector_info>
@@ -54,7 +46,8 @@ struct tcp_dsr_args {
5446

5547

5648
// besides filling in the command line parsing, decide on error handling - possibilities include
57-
// return std::optiona<tcp_dsr_args>, or throwing an exception
49+
// return std::optional<tcp_dsr_args>, or return std::expected<tcp_dsr_args>, or throwing an
50+
// exception
5851
inline tcp_dsr_args parse_command_line (int argc, char* argvp[]) {
5952

6053
}

0 commit comments

Comments
 (0)