mod common;
use std::io::Read;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time;
use crossbeam_channel::{bounded, Sender};
use flate2::read::GzDecoder;
use serde_json::Value as JsonValue;
use glean::net;
use glean::ConfigurationBuilder;
use glean_core::TestGetValue;
pub mod metrics {
#![allow(non_upper_case_globals)]
use glean::{
private::BooleanMetric, private::TimingDistributionMetric, CommonMetricData, Lifetime,
TimeUnit,
};
pub static sample_boolean: once_cell::sync::Lazy<BooleanMetric> =
once_cell::sync::Lazy::new(|| {
BooleanMetric::new(CommonMetricData {
name: "sample_boolean".into(),
category: "test.metrics".into(),
send_in_pings: vec!["validation".into()],
disabled: false,
lifetime: Lifetime::Ping,
..Default::default()
})
});
pub static send_success: once_cell::sync::Lazy<TimingDistributionMetric> =
once_cell::sync::Lazy::new(|| {
TimingDistributionMetric::new(
CommonMetricData {
name: "send_success".into(),
category: "glean.upload".into(),
send_in_pings: vec!["metrics".into()],
lifetime: Lifetime::Ping,
disabled: false,
dynamic_label: None,
},
TimeUnit::Millisecond,
)
});
pub static send_failure: once_cell::sync::Lazy<TimingDistributionMetric> =
once_cell::sync::Lazy::new(|| {
TimingDistributionMetric::new(
CommonMetricData {
name: "send_failure".into(),
category: "glean.upload".into(),
send_in_pings: vec!["metrics".into()],
lifetime: Lifetime::Ping,
disabled: false,
dynamic_label: None,
},
TimeUnit::Millisecond,
)
});
pub static shutdown_wait: once_cell::sync::Lazy<TimingDistributionMetric> =
once_cell::sync::Lazy::new(|| {
TimingDistributionMetric::new(
CommonMetricData {
name: "shutdown_wait".into(),
category: "glean.validation".into(),
send_in_pings: vec!["metrics".into()],
lifetime: Lifetime::Ping,
disabled: false,
dynamic_label: None,
},
TimeUnit::Millisecond,
)
});
}
mod pings {
use super::*;
use glean::private::PingType;
use once_cell::sync::Lazy;
#[allow(non_upper_case_globals)]
pub static validation: Lazy<PingType> = Lazy::new(|| {
common::PingBuilder::new("validation")
.with_send_if_empty(true)
.build()
});
}
#[derive(Debug)]
struct FakeUploader {
calls: AtomicUsize,
sender: Sender<JsonValue>,
}
impl net::PingUploader for FakeUploader {
fn upload(&self, upload_request: net::CapablePingUploadRequest) -> net::UploadResult {
let upload_request = upload_request.capable(|_| true).unwrap();
let calls = self.calls.fetch_add(1, Ordering::SeqCst);
let body = upload_request.body;
let decode = |body: Vec<u8>| {
let mut gzip_decoder = GzDecoder::new(&body[..]);
let mut s = String::with_capacity(body.len());
gzip_decoder
.read_to_string(&mut s)
.ok()
.map(|_| &s[..])
.or_else(|| std::str::from_utf8(&body).ok())
.and_then(|payload| serde_json::from_str(payload).ok())
.unwrap()
};
match calls {
0 => net::UploadResult::http_status(200),
1 => {
thread::sleep(time::Duration::from_millis(100));
net::UploadResult::http_status(200)
}
2 => net::UploadResult::http_status(404),
3 => {
self.sender.send(decode(body)).unwrap();
net::UploadResult::http_status(200)
}
_ => {
self.sender.send(decode(body)).unwrap();
net::UploadResult::http_status(200)
}
}
}
}
#[test]
fn upload_timings() {
common::enable_test_logging();
let dir = tempfile::tempdir().unwrap();
let tmpname = dir.path().to_path_buf();
let (tx, rx) = bounded(1);
let cfg = ConfigurationBuilder::new(true, tmpname.clone(), "glean-upload-timing")
.with_server_endpoint("invalid-test-host")
.with_use_core_mps(false)
.with_uploader(FakeUploader {
calls: AtomicUsize::new(0),
sender: tx,
})
.build();
glean_core::glean_set_test_mode(true);
common::initialize(cfg);
let _ = metrics::sample_boolean.test_get_value(None);
pings::validation.submit(None);
pings::validation.submit(None);
pings::validation.submit(None);
pings::validation.submit(None);
let _body = rx.recv().unwrap();
assert_eq!(
3,
metrics::send_success.test_get_value(None).unwrap().count,
"Successful pings: two fast, one slow"
);
assert_eq!(
1,
metrics::send_failure.test_get_value(None).unwrap().count,
"One failed ping"
);
let data_path = Some(tmpname.display().to_string());
glean_core::glean_test_destroy_glean(false, data_path);
let cfg = ConfigurationBuilder::new(true, tmpname, "glean-upload-timing")
.with_server_endpoint("invalid-test-host")
.with_use_core_mps(false)
.build();
common::initialize(cfg);
assert_eq!(
1,
metrics::shutdown_wait.test_get_value(None).unwrap().count,
"Measured time waiting for shutdown exactly once"
);
}