faucet_sink_stdout/
config.rs1use faucet_core::DEFAULT_BATCH_SIZE;
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
9#[serde(rename_all = "lowercase")]
10pub enum StdStream {
11 #[default]
13 Stdout,
14 Stderr,
16}
17
18#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
20#[serde(rename_all = "snake_case")]
21pub enum StdoutFormat {
22 #[default]
24 JsonLines,
25 PrettyJson,
27 Tsv,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
34pub struct StdoutSinkConfig {
35 #[serde(default)]
37 pub destination: StdStream,
38 #[serde(default)]
40 pub format: StdoutFormat,
41 #[serde(default)]
44 pub flush_per_record: bool,
45 #[serde(default)]
48 pub max_records: Option<usize>,
49 #[serde(default = "default_batch_size")]
60 pub batch_size: usize,
61}
62
63fn default_batch_size() -> usize {
64 DEFAULT_BATCH_SIZE
65}
66
67impl Default for StdoutSinkConfig {
68 fn default() -> Self {
69 Self {
70 destination: StdStream::default(),
71 format: StdoutFormat::default(),
72 flush_per_record: false,
73 max_records: None,
74 batch_size: DEFAULT_BATCH_SIZE,
75 }
76 }
77}
78
79impl StdoutSinkConfig {
80 pub fn new() -> Self {
82 Self::default()
83 }
84
85 pub fn destination(mut self, destination: StdStream) -> Self {
87 self.destination = destination;
88 self
89 }
90
91 pub fn format(mut self, format: StdoutFormat) -> Self {
93 self.format = format;
94 self
95 }
96
97 pub fn flush_per_record(mut self, flush_per_record: bool) -> Self {
99 self.flush_per_record = flush_per_record;
100 self
101 }
102
103 pub fn max_records(mut self, max_records: usize) -> Self {
105 self.max_records = Some(max_records);
106 self
107 }
108
109 pub fn with_batch_size(mut self, batch_size: usize) -> Self {
118 self.batch_size = batch_size;
119 self
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn defaults() {
129 let c = StdoutSinkConfig::new();
130 assert_eq!(c.destination, StdStream::Stdout);
131 assert_eq!(c.format, StdoutFormat::JsonLines);
132 assert!(!c.flush_per_record);
133 assert!(c.max_records.is_none());
134 }
135
136 #[test]
137 fn builder_chains() {
138 let c = StdoutSinkConfig::new()
139 .destination(StdStream::Stderr)
140 .format(StdoutFormat::PrettyJson)
141 .flush_per_record(true)
142 .max_records(10);
143 assert_eq!(c.destination, StdStream::Stderr);
144 assert_eq!(c.format, StdoutFormat::PrettyJson);
145 assert!(c.flush_per_record);
146 assert_eq!(c.max_records, Some(10));
147 }
148
149 #[test]
150 fn serde_round_trip() {
151 let c = StdoutSinkConfig::new()
152 .destination(StdStream::Stderr)
153 .format(StdoutFormat::Tsv);
154 let json = serde_json::to_string(&c).unwrap();
155 let back: StdoutSinkConfig = serde_json::from_str(&json).unwrap();
156 assert_eq!(back.destination, StdStream::Stderr);
157 assert_eq!(back.format, StdoutFormat::Tsv);
158 }
159
160 #[test]
161 fn deserialize_from_minimal_json() {
162 let c: StdoutSinkConfig = serde_json::from_str("{}").unwrap();
163 assert_eq!(c.destination, StdStream::Stdout);
164 assert_eq!(c.format, StdoutFormat::JsonLines);
165 }
166
167 #[test]
168 fn batch_size_defaults_to_default_batch_size() {
169 let c = StdoutSinkConfig::new();
170 assert_eq!(c.batch_size, faucet_core::DEFAULT_BATCH_SIZE);
171 }
172
173 #[test]
174 fn with_batch_size_overrides_default() {
175 let c = StdoutSinkConfig::new().with_batch_size(250);
176 assert_eq!(c.batch_size, 250);
177 }
178
179 #[test]
180 fn batch_size_zero_is_accepted_as_no_batching_sentinel() {
181 let c = StdoutSinkConfig::new().with_batch_size(0);
182 assert_eq!(c.batch_size, 0);
183 assert!(faucet_core::validate_batch_size(c.batch_size).is_ok());
184 }
185
186 #[test]
187 fn batch_size_above_max_is_rejected_by_validate_batch_size() {
188 let c = StdoutSinkConfig::new().with_batch_size(faucet_core::MAX_BATCH_SIZE + 1);
189 assert!(faucet_core::validate_batch_size(c.batch_size).is_err());
190 }
191
192 #[test]
193 fn batch_size_deserializes_from_json() {
194 let json = r#"{
195 "destination": "stdout",
196 "format": "json_lines",
197 "batch_size": 500
198 }"#;
199 let c: StdoutSinkConfig = serde_json::from_str(json).unwrap();
200 assert_eq!(c.batch_size, 500);
201 }
202
203 #[test]
204 fn batch_size_defaults_when_missing_in_json() {
205 let c: StdoutSinkConfig = serde_json::from_str("{}").unwrap();
206 assert_eq!(c.batch_size, faucet_core::DEFAULT_BATCH_SIZE);
207 }
208}