schema::{Name, RecordField, RecordFieldOrder, Schema, UnionSchema},
types::Value,
};
- use log::{Level, LevelFilter, Metadata};
+ use apache_avro_test_helper::logger::assert_logged;
use uuid::Uuid;
- use ref_thread_local::{ref_thread_local, RefThreadLocal};
-
- ref_thread_local! {
- // The unit tests run in parallel
- // We need to keep the log messages in a thread-local variable
- // and clear them after assertion
- static managed LOG_MESSAGES: Vec<String> = Vec::new();
- }
-
- struct TestLogger;
-
- impl log::Log for TestLogger {
- fn enabled(&self, metadata: &Metadata) -> bool {
- metadata.level() <= Level::Error
- }
-
- fn log(&self, record: &log::Record) {
- if self.enabled(record.metadata()) {
- let mut msgs = LOG_MESSAGES.borrow_mut();
- msgs.push(format!("{}", record.args()));
- }
- }
-
- fn flush(&self) {}
- }
-
- static TEST_LOGGER: TestLogger = TestLogger;
-
- fn init() {
- let _ = log::set_logger(&TEST_LOGGER);
- log::set_max_level(LevelFilter::Info);
- }
-
- fn assert_log_message(expected_message: &str) {
- let mut msgs = LOG_MESSAGES.borrow_mut();
- assert_eq!(msgs.pop().unwrap(), expected_message);
- msgs.clear();
- }
-
#[test]
fn validate() {
let value_schema_valid = vec![
#[test]
fn validate_fixed() {
- init();
-
let schema = Schema::Fixed {
size: 4,
name: Name::new("some_fixed").unwrap(),
assert!(Value::Fixed(4, vec![0, 0, 0, 0]).validate(&schema));
let value = Value::Fixed(5, vec![0, 0, 0, 0, 0]);
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
format!(
"Invalid value: {:?} for schema: {:?}. Reason: {}",
value, schema, "The value's size (5) is different than the schema's size (4)"
assert!(Value::Bytes(vec![0, 0, 0, 0]).validate(&schema));
let value = Value::Bytes(vec![0, 0, 0, 0, 0]);
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
format!(
"Invalid value: {:?} for schema: {:?}. Reason: {}",
value, schema, "The bytes' length (5) is different than the schema's size (4)"
#[test]
fn validate_enum() {
- init();
-
let schema = Schema::Enum {
name: Name::new("some_enum").unwrap(),
aliases: None,
let value = Value::Enum(1, "spades".to_string());
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
format!(
"Invalid value: {:?} for schema: {:?}. Reason: {}",
value, schema, "Symbol 'spades' is not at position '1'"
let value = Value::Enum(1000, "spades".to_string());
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
format!(
"Invalid value: {:?} for schema: {:?}. Reason: {}",
value, schema, "No symbol at position '1000'"
let value = Value::String("lorem".to_string());
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
format!(
"Invalid value: {:?} for schema: {:?}. Reason: {}",
value, schema, "'lorem' is not a member of the possible symbols"
let value = Value::Enum(0, "spades".to_string());
assert!(!value.validate(&other_schema));
- assert_log_message(
+ assert_logged(
format!(
"Invalid value: {:?} for schema: {:?}. Reason: {}",
value, other_schema, "Symbol 'spades' is not at position '0'"
#[test]
fn validate_record() {
- init();
-
// {
// "type": "record",
// "fields": [
("b".to_string(), Value::String("foo".to_string())),
]);
assert!(!value.validate(&schema));
- assert_log_message("Invalid value: Record([(\"a\", Boolean(false)), (\"b\", String(\"foo\"))]) for schema: Record { name: Name { name: \"some_record\", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: \"a\", doc: None, default: None, schema: Long, order: Ascending, position: 0 }, RecordField { name: \"b\", doc: None, default: None, schema: String, order: Ascending, position: 1 }], lookup: {\"a\": 0, \"b\": 1} }. Reason: Unsupported value-schema combination");
+ assert_logged("Invalid value: Record([(\"a\", Boolean(false)), (\"b\", String(\"foo\"))]) for schema: Record { name: Name { name: \"some_record\", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: \"a\", doc: None, default: None, schema: Long, order: Ascending, position: 0 }, RecordField { name: \"b\", doc: None, default: None, schema: String, order: Ascending, position: 1 }], lookup: {\"a\": 0, \"b\": 1} }. Reason: Unsupported value-schema combination");
let value = Value::Record(vec![
("a".to_string(), Value::Long(42i64)),
("c".to_string(), Value::String("foo".to_string())),
]);
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
"Invalid value: Record([(\"a\", Long(42)), (\"c\", String(\"foo\"))]) for schema: Record { name: Name { name: \"some_record\", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: \"a\", doc: None, default: None, schema: Long, order: Ascending, position: 0 }, RecordField { name: \"b\", doc: None, default: None, schema: String, order: Ascending, position: 1 }], lookup: {\"a\": 0, \"b\": 1} }. Reason: There is no schema field for field 'c'"
);
("c".to_string(), Value::Null),
]);
assert!(!value.validate(&schema));
- assert_log_message(
+ assert_logged(
r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), ("c", Null)]) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, default: None, schema: Long, order: Ascending, position: 0 }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1 }], lookup: {"a": 0, "b": 1} }. Reason: The value's records length (3) is different than the schema's (2)"#,
);
.collect()
)
.validate(&schema));
- assert_log_message(
+ assert_logged(
r#"Invalid value: Map({"c": Long(123)}) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, default: None, schema: Long, order: Ascending, position: 0 }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1 }], lookup: {"a": 0, "b": 1} }. Reason: Field with name '"a"' is not a member of the map items
Field with name '"b"' is not a member of the map items"#,
);
Codec, Error, Reader, Schema, Writer,
};
use lazy_static::lazy_static;
-use log::debug;
-
-fn init() {
- let _ = env_logger::builder()
- .filter_level(log::LevelFilter::Trace)
- .is_test(true)
- .try_init();
-}
+use apache_avro_test_helper::init;
const PRIMITIVE_EXAMPLES: &[(&str, bool)] = &[
(r#""null""#, true),
#[test]
fn test_parse() {
init();
-
for (raw_schema, valid) in EXAMPLES.iter() {
let schema = Schema::parse_str(raw_schema);
if *valid {
#[test]
fn test_doc_attributes() {
init();
-
fn assert_doc(schema: &Schema) {
match schema {
Schema::Enum { doc, .. } => assert!(doc.is_some()),
#[test]
fn test_root_error_is_not_swallowed_on_parse_error() -> Result<(), String> {
init();
-
let raw_schema = r#"/not/a/real/file"#;
let error = Schema::parse_str(raw_schema).unwrap_err();
// AVRO-3302
#[test]
fn test_record_schema_with_cyclic_references() {
+ init();
let schema = Schema::parse_str(
r#"
{
match Reader::new(&mut bytes.as_slice()) {
Ok(mut reader) => match reader.next() {
- Some(value) => debug!("{:?}", value.unwrap()),
+ Some(value) => log::debug!("{:?}", value.unwrap()),
None => panic!("No value was read!"),
},
Err(err) => panic!("An error occurred while reading datum: {:?}", err),
// TODO: (#93) add support for logical type and attributes and uncomment (may need some tweaks to compile)
#[test]
fn test_decimal_valid_type_attributes() {
+ init();
let fixed_decimal = Schema::parse_str(DECIMAL_LOGICAL_TYPE_ATTRIBUTES[0]).unwrap();
assert_eq!(4, fixed_decimal.get_attribute("precision"));
assert_eq!(2, fixed_decimal.get_attribute("scale"));