mod common;
use std::collections::HashMap;
use billdogeng::{BilldogEng, BilldogEngOptions};
use common::{start_stub, StubResponse};
use serde_json::json;
fn opts(host: &str, flush_at: usize) -> BilldogEngOptions {
BilldogEngOptions {
host: host.to_string(),
flush_at,
..Default::default()
}
}
#[test]
fn ten_captures_produce_one_batched_post_of_ten() {
let stub = start_stub(|_req, _hit| {
StubResponse::envelope(json!({ "processed": 10, "duplicates": 0, "invalid": 0 }))
});
let bd = BilldogEng::new("bd_test_x", opts(&stub.url, 100));
for i in 0..10 {
let mut props = serde_json::Map::new();
props.insert("n".to_string(), json!(i));
bd.capture("user-123", "order_completed", props, HashMap::new());
}
assert_eq!(bd.queue_length(), 10);
bd.flush().unwrap();
bd.shutdown().unwrap();
let ingest = stub.requests_for("/ingest-events");
assert_eq!(ingest.len(), 1, "exactly one POST to /ingest-events");
let body = ingest[0].body.as_ref().unwrap();
assert_eq!(body["api_key"], json!("bd_test_x"));
let events = body["events"].as_array().unwrap();
assert_eq!(events.len(), 10);
let ev = &events[0];
assert_eq!(ev["event_name"], json!("order_completed"));
assert_eq!(ev["user_id"], json!("user-123"));
assert!(ev["event_timestamp"].is_number());
assert_eq!(ev["properties"]["n"], json!(0));
assert_eq!(ingest[0].header("x-api-key"), Some("bd_test_x"));
}
#[test]
fn auto_flushes_when_queue_reaches_flush_at() {
let stub = start_stub(|_req, _hit| StubResponse::envelope(json!({ "processed": 5 })));
let bd = BilldogEng::new("bd_test_x", opts(&stub.url, 5));
for i in 0..5 {
let mut props = serde_json::Map::new();
props.insert("i".to_string(), json!(i));
bd.capture("u", "e", props, HashMap::new());
}
bd.flush().unwrap();
bd.shutdown().unwrap();
let ingest = stub.requests_for("/ingest-events");
assert!(!ingest.is_empty());
let total: usize = ingest
.iter()
.map(|r| r.body.as_ref().unwrap()["events"].as_array().unwrap().len())
.sum();
assert_eq!(total, 5);
}
#[test]
fn identify_emits_set() {
let stub = start_stub(|_req, _hit| StubResponse::envelope(json!({ "processed": 1 })));
let bd = BilldogEng::new("bd_test_x", opts(&stub.url, 100));
let props = json!({ "email": "a@b.com", "plan": "pro" })
.as_object()
.unwrap()
.clone();
bd.identify("user-123", props);
bd.flush().unwrap();
bd.shutdown().unwrap();
let reqs = stub.requests();
let ev = &reqs[0].body.as_ref().unwrap()["events"][0];
assert_eq!(ev["event_name"], json!("$identify"));
assert_eq!(ev["user_id"], json!("user-123"));
assert_eq!(ev["properties"]["$set"], json!({ "email": "a@b.com", "plan": "pro" }));
}
#[test]
fn group_identify_emits_type_key_set() {
let stub = start_stub(|_req, _hit| StubResponse::envelope(json!({ "processed": 1 })));
let bd = BilldogEng::new("bd_test_x", opts(&stub.url, 100));
let props = json!({ "seats": 50 }).as_object().unwrap().clone();
bd.group_identify("company", "acme", props);
bd.flush().unwrap();
bd.shutdown().unwrap();
let reqs = stub.requests();
let ev = &reqs[0].body.as_ref().unwrap()["events"][0];
assert_eq!(ev["event_name"], json!("$groupidentify"));
assert_eq!(ev["user_id"], json!("acme"));
assert_eq!(ev["properties"]["$group_type"], json!("company"));
assert_eq!(ev["properties"]["$group_key"], json!("acme"));
assert_eq!(ev["properties"]["$group_set"], json!({ "seats": 50 }));
}
#[test]
fn alias_emits_create_alias() {
let stub = start_stub(|_req, _hit| StubResponse::envelope(json!({ "processed": 1 })));
let bd = BilldogEng::new("bd_test_x", opts(&stub.url, 100));
bd.alias("user-123", "anon-abc");
bd.flush().unwrap();
bd.shutdown().unwrap();
let reqs = stub.requests();
let ev = &reqs[0].body.as_ref().unwrap()["events"][0];
assert_eq!(ev["event_name"], json!("$create_alias"));
assert_eq!(ev["properties"]["alias"], json!("anon-abc"));
}
#[test]
fn capture_mirrors_groups_into_groups_and_positional() {
let stub = start_stub(|_req, _hit| StubResponse::envelope(json!({ "processed": 1 })));
let mut index = HashMap::new();
index.insert("company".to_string(), 0u8);
index.insert("team".to_string(), 1u8);
let bd = BilldogEng::new(
"bd_test_x",
BilldogEngOptions {
host: stub.url.clone(),
flush_at: 100,
group_type_index: Some(index),
..Default::default()
},
);
let mut props = serde_json::Map::new();
props.insert("x".to_string(), json!(1));
let mut groups = HashMap::new();
groups.insert("company".to_string(), "acme".to_string());
groups.insert("team".to_string(), "core".to_string());
bd.capture("user-123", "event", props, groups);
bd.flush().unwrap();
bd.shutdown().unwrap();
let reqs = stub.requests();
let ev = &reqs[0].body.as_ref().unwrap()["events"][0];
let p = &ev["properties"];
assert_eq!(p["$groups"], json!({ "company": "acme", "team": "core" }));
assert_eq!(p["$group_0"], json!("acme"));
assert_eq!(p["$group_1"], json!("core"));
}