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 Csv,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
40pub struct StdoutSinkConfig {
41 #[serde(default)]
43 pub destination: StdStream,
44 #[serde(default)]
46 pub format: StdoutFormat,
47 #[serde(default)]
50 pub flush_per_record: bool,
51 #[serde(default)]
54 pub max_records: Option<usize>,
55 #[serde(default = "default_batch_size")]
66 pub batch_size: usize,
67}
68
69fn default_batch_size() -> usize {
70 DEFAULT_BATCH_SIZE
71}
72
73impl Default for StdoutSinkConfig {
74 fn default() -> Self {
75 Self {
76 destination: StdStream::default(),
77 format: StdoutFormat::default(),
78 flush_per_record: false,
79 max_records: None,
80 batch_size: DEFAULT_BATCH_SIZE,
81 }
82 }
83}
84
85impl StdoutSinkConfig {
86 pub fn new() -> Self {
88 Self::default()
89 }
90
91 pub fn destination(mut self, destination: StdStream) -> Self {
93 self.destination = destination;
94 self
95 }
96
97 pub fn format(mut self, format: StdoutFormat) -> Self {
99 self.format = format;
100 self
101 }
102
103 pub fn flush_per_record(mut self, flush_per_record: bool) -> Self {
105 self.flush_per_record = flush_per_record;
106 self
107 }
108
109 pub fn max_records(mut self, max_records: usize) -> Self {
111 self.max_records = Some(max_records);
112 self
113 }
114
115 pub fn with_batch_size(mut self, batch_size: usize) -> Self {
124 self.batch_size = batch_size;
125 self
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn defaults() {
135 let c = StdoutSinkConfig::new();
136 assert_eq!(c.destination, StdStream::Stdout);
137 assert_eq!(c.format, StdoutFormat::JsonLines);
138 assert!(!c.flush_per_record);
139 assert!(c.max_records.is_none());
140 }
141
142 #[test]
143 fn builder_chains() {
144 let c = StdoutSinkConfig::new()
145 .destination(StdStream::Stderr)
146 .format(StdoutFormat::PrettyJson)
147 .flush_per_record(true)
148 .max_records(10);
149 assert_eq!(c.destination, StdStream::Stderr);
150 assert_eq!(c.format, StdoutFormat::PrettyJson);
151 assert!(c.flush_per_record);
152 assert_eq!(c.max_records, Some(10));
153 }
154
155 #[test]
156 fn serde_round_trip() {
157 let c = StdoutSinkConfig::new()
158 .destination(StdStream::Stderr)
159 .format(StdoutFormat::Tsv);
160 let json = serde_json::to_string(&c).unwrap();
161 let back: StdoutSinkConfig = serde_json::from_str(&json).unwrap();
162 assert_eq!(back.destination, StdStream::Stderr);
163 assert_eq!(back.format, StdoutFormat::Tsv);
164 }
165
166 #[test]
167 fn deserialize_from_minimal_json() {
168 let c: StdoutSinkConfig = serde_json::from_str("{}").unwrap();
169 assert_eq!(c.destination, StdStream::Stdout);
170 assert_eq!(c.format, StdoutFormat::JsonLines);
171 }
172
173 #[test]
174 fn batch_size_defaults_to_default_batch_size() {
175 let c = StdoutSinkConfig::new();
176 assert_eq!(c.batch_size, faucet_core::DEFAULT_BATCH_SIZE);
177 }
178
179 #[test]
180 fn with_batch_size_overrides_default() {
181 let c = StdoutSinkConfig::new().with_batch_size(250);
182 assert_eq!(c.batch_size, 250);
183 }
184
185 #[test]
186 fn batch_size_zero_is_accepted_as_no_batching_sentinel() {
187 let c = StdoutSinkConfig::new().with_batch_size(0);
188 assert_eq!(c.batch_size, 0);
189 assert!(faucet_core::validate_batch_size(c.batch_size).is_ok());
190 }
191
192 #[test]
193 fn batch_size_above_max_is_rejected_by_validate_batch_size() {
194 let c = StdoutSinkConfig::new().with_batch_size(faucet_core::MAX_BATCH_SIZE + 1);
195 assert!(faucet_core::validate_batch_size(c.batch_size).is_err());
196 }
197
198 #[test]
199 fn batch_size_deserializes_from_json() {
200 let json = r#"{
201 "destination": "stdout",
202 "format": "json_lines",
203 "batch_size": 500
204 }"#;
205 let c: StdoutSinkConfig = serde_json::from_str(json).unwrap();
206 assert_eq!(c.batch_size, 500);
207 }
208
209 #[test]
210 fn batch_size_defaults_when_missing_in_json() {
211 let c: StdoutSinkConfig = serde_json::from_str("{}").unwrap();
212 assert_eq!(c.batch_size, faucet_core::DEFAULT_BATCH_SIZE);
213 }
214}