Browse Source

Add Tests

This moves a large chunk of code from ebpf to shared so we can re-use
write_record_header and write_record_message and friends so that we
can write test cases to ensure that logs are properly formatted
given certain input.

Signed-off-by: Dave Tucker <[email protected]>
Dave Tucker 2 years ago
parent
commit
5d82d9a

+ 105 - 0
aya-log/aya-log-common/src/lib.rs

@@ -1,5 +1,7 @@
 #![no_std]
 
+use core::{cmp, mem, ptr};
+
 pub const LOG_BUF_CAPACITY: usize = 8192;
 
 pub const LOG_FIELDS: usize = 7;
@@ -71,3 +73,106 @@ mod userspace {
     unsafe impl aya::Pod for RecordField {}
     unsafe impl aya::Pod for ArgType {}
 }
+
+struct TagLenValue<'a, T> {
+    tag: T,
+    value: &'a [u8],
+}
+
+impl<'a, T> TagLenValue<'a, T>
+where
+    T: Copy,
+{
+    #[inline(always)]
+    pub(crate) fn new(tag: T, value: &'a [u8]) -> TagLenValue<'a, T> {
+        TagLenValue { tag, value }
+    }
+
+    pub(crate) fn write(&self, mut buf: &mut [u8]) -> Result<usize, ()> {
+        let size = mem::size_of::<T>() + mem::size_of::<usize>() + self.value.len();
+        if buf.len() < size {
+            return Err(());
+        }
+
+        unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.tag) };
+        buf = &mut buf[mem::size_of::<T>()..];
+
+        unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.value.len()) };
+        buf = &mut buf[mem::size_of::<usize>()..];
+
+        let len = cmp::min(buf.len(), self.value.len());
+        buf[..len].copy_from_slice(&self.value[..len]);
+        Ok(size)
+    }
+}
+
+pub trait WriteToBuf {
+    #[allow(clippy::result_unit_err)]
+    fn write(&self, buf: &mut [u8]) -> Result<usize, ()>;
+}
+
+macro_rules! impl_write_to_buf {
+    ($type:ident, $arg_type:expr) => {
+        impl WriteToBuf for $type {
+            fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
+                TagLenValue::<ArgType>::new($arg_type, &self.to_ne_bytes()).write(buf)
+            }
+        }
+    };
+}
+
+impl_write_to_buf!(i8, ArgType::I8);
+impl_write_to_buf!(i16, ArgType::I16);
+impl_write_to_buf!(i32, ArgType::I32);
+impl_write_to_buf!(i64, ArgType::I64);
+impl_write_to_buf!(i128, ArgType::I128);
+impl_write_to_buf!(isize, ArgType::Isize);
+
+impl_write_to_buf!(u8, ArgType::U8);
+impl_write_to_buf!(u16, ArgType::U16);
+impl_write_to_buf!(u32, ArgType::U32);
+impl_write_to_buf!(u64, ArgType::U64);
+impl_write_to_buf!(u128, ArgType::U128);
+impl_write_to_buf!(usize, ArgType::Usize);
+
+impl_write_to_buf!(f32, ArgType::F32);
+impl_write_to_buf!(f64, ArgType::F64);
+
+impl WriteToBuf for str {
+    fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
+        TagLenValue::<ArgType>::new(ArgType::Str, self.as_bytes()).write(buf)
+    }
+}
+
+#[allow(clippy::result_unit_err)]
+#[doc(hidden)]
+#[inline(always)]
+pub fn write_record_header(
+    buf: &mut [u8],
+    target: &str,
+    level: Level,
+    module: &str,
+    file: &str,
+    line: u32,
+    num_args: usize,
+) -> Result<usize, ()> {
+    let mut size = 0;
+    for attr in [
+        TagLenValue::<RecordField>::new(RecordField::Target, target.as_bytes()),
+        TagLenValue::<RecordField>::new(RecordField::Level, &(level as usize).to_ne_bytes()),
+        TagLenValue::<RecordField>::new(RecordField::Module, module.as_bytes()),
+        TagLenValue::<RecordField>::new(RecordField::File, file.as_bytes()),
+        TagLenValue::<RecordField>::new(RecordField::Line, &line.to_ne_bytes()),
+        TagLenValue::<RecordField>::new(RecordField::NumArgs, &num_args.to_ne_bytes()),
+    ] {
+        size += attr.write(&mut buf[size..])?;
+    }
+
+    Ok(size)
+}
+
+#[allow(clippy::result_unit_err)]
+#[doc(hidden)]
+pub fn write_record_message(buf: &mut [u8], msg: &str) -> Result<usize, ()> {
+    TagLenValue::<RecordField>::new(RecordField::Log, msg.as_bytes()).write(buf)
+}

+ 4 - 0
aya-log/aya-log/Cargo.toml

@@ -19,5 +19,9 @@ log = "0.4"
 bytes = "1.1"
 tokio = { version = "1.2.0" }
 
+[dev-dependencies]
+simplelog = "0.12"
+testing_logger = "0.1.1"
+
 [lib]
 path = "src/lib.rs"

+ 52 - 1
aya-log/aya-log/src/lib.rs

@@ -34,7 +34,7 @@
 //!
 //! With the following eBPF code:
 //!
-//! ```no_run
+//! ```ignore
 //! # let ctx = ();
 //! use aya_log_ebpf::{debug, error, info, trace, warn};
 //!
@@ -328,3 +328,54 @@ impl<'a, T: Pod> TagLenValue<'a, T> {
         ))
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use aya_log_common::{write_record_header, write_record_message, WriteToBuf};
+    use log::logger;
+    use testing_logger;
+
+    fn new_log(msg: &str, args: usize) -> Result<(usize, Vec<u8>), ()> {
+        let mut buf = vec![0; 8192];
+        let mut len = write_record_header(
+            &mut buf,
+            "test",
+            aya_log_common::Level::Info,
+            "test",
+            "test.rs",
+            123,
+            args,
+        )?;
+        len += write_record_message(&mut buf[len..], msg)?;
+        Ok((len, buf))
+    }
+
+    #[test]
+    fn test_str() {
+        testing_logger::setup();
+        let (_, input) = new_log("test", 0).unwrap();
+        let logger = logger();
+        let _ = log_buf(&input, logger);
+        testing_logger::validate(|captured_logs| {
+            assert_eq!(captured_logs.len(), 1);
+            assert_eq!(captured_logs[0].body, "test");
+            assert_eq!(captured_logs[0].level, Level::Info);
+        });
+    }
+
+    #[test]
+    fn test_str_with_args() {
+        testing_logger::setup();
+        let (len, mut input) = new_log("hello {}", 1).unwrap();
+        let name = "test";
+        (*name).write(&mut input[len..]).unwrap();
+        let logger = logger();
+        let _ = log_buf(&input, logger);
+        testing_logger::validate(|captured_logs| {
+            assert_eq!(captured_logs.len(), 1);
+            assert_eq!(captured_logs[0].body, "hello test");
+            assert_eq!(captured_logs[0].level, Level::Info);
+        });
+    }
+}

+ 2 - 109
aya-log/ebpf/aya-log-ebpf/src/lib.rs

@@ -1,13 +1,9 @@
 #![no_std]
-
-use core::{cmp, mem, ptr};
-
 use aya_bpf::{
     macros::map,
-    maps::{PerCpuArray, PerfEventByteArray},
+    maps::{PerCpuArray, PerfEventByteArray}
 };
-use aya_log_common::{ArgType, RecordField};
-pub use aya_log_common::{Level, LOG_BUF_CAPACITY};
+pub use aya_log_common::{Level, LOG_BUF_CAPACITY, write_record_header, write_record_message, WriteToBuf};
 pub use aya_log_ebpf_macros::{debug, error, info, log, trace, warn};
 
 #[doc(hidden)]
@@ -24,109 +20,6 @@ pub static mut AYA_LOG_BUF: PerCpuArray<LogBuf> = PerCpuArray::with_max_entries(
 #[map]
 pub static mut AYA_LOGS: PerfEventByteArray = PerfEventByteArray::new(0);
 
-struct TagLenValue<'a, T> {
-    tag: T,
-    value: &'a [u8],
-}
-
-impl<'a, T> TagLenValue<'a, T>
-where
-    T: Copy,
-{
-    #[inline(always)]
-    pub(crate) fn new(tag: T, value: &'a [u8]) -> TagLenValue<'a, T> {
-        TagLenValue { tag, value }
-    }
-
-    pub(crate) fn write(&self, mut buf: &mut [u8]) -> Result<usize, ()> {
-        let size = mem::size_of::<T>() + mem::size_of::<usize>() + self.value.len();
-        if buf.len() < size {
-            return Err(());
-        }
-
-        unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.tag) };
-        buf = &mut buf[mem::size_of::<T>()..];
-
-        unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.value.len()) };
-        buf = &mut buf[mem::size_of::<usize>()..];
-
-        let len = cmp::min(buf.len(), self.value.len());
-        buf[..len].copy_from_slice(&self.value[..len]);
-        Ok(size)
-    }
-}
-
-pub trait WriteToBuf {
-    #[allow(clippy::result_unit_err)]
-    fn write(&self, buf: &mut [u8]) -> Result<usize, ()>;
-}
-
-macro_rules! impl_write_to_buf {
-    ($type:ident, $arg_type:expr) => {
-        impl WriteToBuf for $type {
-            fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
-                TagLenValue::<ArgType>::new($arg_type, &self.to_ne_bytes()).write(buf)
-            }
-        }
-    };
-}
-
-impl_write_to_buf!(i8, ArgType::I8);
-impl_write_to_buf!(i16, ArgType::I16);
-impl_write_to_buf!(i32, ArgType::I32);
-impl_write_to_buf!(i64, ArgType::I64);
-impl_write_to_buf!(i128, ArgType::I128);
-impl_write_to_buf!(isize, ArgType::Isize);
-
-impl_write_to_buf!(u8, ArgType::U8);
-impl_write_to_buf!(u16, ArgType::U16);
-impl_write_to_buf!(u32, ArgType::U32);
-impl_write_to_buf!(u64, ArgType::U64);
-impl_write_to_buf!(u128, ArgType::U128);
-impl_write_to_buf!(usize, ArgType::Usize);
-
-impl_write_to_buf!(f32, ArgType::F32);
-impl_write_to_buf!(f64, ArgType::F64);
-
-impl WriteToBuf for str {
-    fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
-        TagLenValue::<ArgType>::new(ArgType::Str, self.as_bytes()).write(buf)
-    }
-}
-
-#[allow(clippy::result_unit_err)]
-#[doc(hidden)]
-#[inline(always)]
-pub fn write_record_header(
-    buf: &mut [u8],
-    target: &str,
-    level: Level,
-    module: &str,
-    file: &str,
-    line: u32,
-    num_args: usize,
-) -> Result<usize, ()> {
-    let mut size = 0;
-    for attr in [
-        TagLenValue::<RecordField>::new(RecordField::Target, target.as_bytes()),
-        TagLenValue::<RecordField>::new(RecordField::Level, &(level as usize).to_ne_bytes()),
-        TagLenValue::<RecordField>::new(RecordField::Module, module.as_bytes()),
-        TagLenValue::<RecordField>::new(RecordField::File, file.as_bytes()),
-        TagLenValue::<RecordField>::new(RecordField::Line, &line.to_ne_bytes()),
-        TagLenValue::<RecordField>::new(RecordField::NumArgs, &num_args.to_ne_bytes()),
-    ] {
-        size += attr.write(&mut buf[size..])?;
-    }
-
-    Ok(size)
-}
-
-#[allow(clippy::result_unit_err)]
-#[doc(hidden)]
-pub fn write_record_message(buf: &mut [u8], msg: &str) -> Result<usize, ()> {
-    TagLenValue::<RecordField>::new(RecordField::Log, msg.as_bytes()).write(buf)
-}
-
 #[doc(hidden)]
 pub mod macro_support {
     pub use aya_log_common::{Level, LOG_BUF_CAPACITY};