From 29f7228ba5ad63d1858f13971fb315624221d726 Mon Sep 17 00:00:00 2001 From: leodziki Date: Sun, 10 Nov 2024 02:29:33 -0800 Subject: [PATCH] Update coverage for error and config Update coverage rate to 80-100% for nativelink-error and nativelink-config --- nativelink-config/Cargo.toml | 2 +- .../tests/deserialization_test.rs | 208 +++++++- nativelink-error/Cargo.toml | 8 +- nativelink-error/tests/lib_test.rs | 450 ++++++++++++++++++ nativelink-metric-collector/src/lib.rs | 2 +- 5 files changed, 652 insertions(+), 18 deletions(-) create mode 100644 nativelink-error/tests/lib_test.rs diff --git a/nativelink-config/Cargo.toml b/nativelink-config/Cargo.toml index 94428da49..c4881854b 100644 --- a/nativelink-config/Cargo.toml +++ b/nativelink-config/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] byte-unit = { version = "5.1.4", default-features = false, features = ["byte"] } humantime = "2.1.0" -serde = { version = "1.0.210", default-features = false } +serde = { version = "1.0.210", default-features = false, features = ["derive"] } serde_json5 = "0.1.0" shellexpand = { version = "3.1.0", default-features = false, features = ["base-0"] } diff --git a/nativelink-config/tests/deserialization_test.rs b/nativelink-config/tests/deserialization_test.rs index 872600893..92e2cf416 100644 --- a/nativelink-config/tests/deserialization_test.rs +++ b/nativelink-config/tests/deserialization_test.rs @@ -14,10 +14,26 @@ use nativelink_config::serde_utils::{ convert_data_size_with_shellexpand, convert_duration_with_shellexpand, + convert_numeric_with_shellexpand, convert_optional_numeric_with_shellexpand, + convert_optional_string_with_shellexpand, convert_string_with_shellexpand, + convert_vec_string_with_shellexpand, }; use pretty_assertions::assert_eq; use serde::Deserialize; +const INVALID_ENV_VAR_ERROR: &str = + "error looking key 'INVALID_ENV_VAR' up: environment variable not found"; +const MAP_TYPE_ERROR: &str = "invalid type: map, expected a string containing json data"; + +const DURATION_HUMAN_READABLE: &str = r#"{"duration": "1m 10s"}"#; +const DURATION_USIZE: &str = r#"{"duration": 10}"#; +const DATA_SIZE_KIB: &str = r#"{"data_size": "1KiB"}"#; +const DATA_SIZE_USIZE: &str = r#"{"data_size": 10}"#; +const STRING_ENV_VAR: &str = r#"{"expanded_string": "$INVALID_ENV_VAR"}"#; +const EMPTY_STRING_ENV_VAR: &str = r#"{"expanded_string": ""}"#; +const NULL_STRING_ENV_VAR: &str = r#"{"expanded_string": null}"#; +const VEC_STRING_EMPTY: &str = r#"{"expanded_strings": []}"#; + #[derive(Deserialize)] struct DurationEntity { #[serde(default, deserialize_with = "convert_duration_with_shellexpand")] @@ -30,38 +46,206 @@ struct DataSizeEntity { data_size: usize, } +#[derive(Deserialize)] +struct NumericEntity { + #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] + value: usize, +} + +#[derive(Deserialize)] +struct OptionalNumericEntity { + #[serde( + default, + deserialize_with = "convert_optional_numeric_with_shellexpand" + )] + optional_value: Option, +} + +#[derive(Deserialize)] +struct VecStringEntity { + #[serde(deserialize_with = "convert_vec_string_with_shellexpand")] + expanded_strings: Vec, +} + +#[derive(Deserialize)] +struct OptionalStringEntity { + #[serde(deserialize_with = "convert_optional_string_with_shellexpand")] + expanded_string: Option, +} + +#[derive(Deserialize)] +struct StringEntity { + #[serde(deserialize_with = "convert_string_with_shellexpand")] + expanded_string: String, +} + #[test] fn test_duration_human_readable_deserialize() { - let example = r#" - {"duration": "1m 10s"} - "#; + let example = DURATION_HUMAN_READABLE; let deserialized: DurationEntity = serde_json5::from_str(example).unwrap(); assert_eq!(deserialized.duration, 70); } #[test] fn test_duration_usize_deserialize() { - let example = r#" - {"duration": 10} - "#; + let example = DURATION_USIZE; let deserialized: DurationEntity = serde_json5::from_str(example).unwrap(); assert_eq!(deserialized.duration, 10); } +#[test] +fn test_duration_invalid_string() { + let example = r#"{"duration": {size:10, in:8}}"#; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), MAP_TYPE_ERROR); + } +} + #[test] fn test_data_size_unit_deserialize() { - let example = r#" - {"data_size": "1KiB"} - "#; + let example = DATA_SIZE_KIB; let deserialized: DataSizeEntity = serde_json5::from_str(example).unwrap(); assert_eq!(deserialized.data_size, 1024); } #[test] fn test_data_size_usize_deserialize() { - let example = r#" - {"data_size": 10} - "#; + let example = DATA_SIZE_USIZE; let deserialized: DataSizeEntity = serde_json5::from_str(example).unwrap(); assert_eq!(deserialized.data_size, 10); } + +#[test] +fn test_data_size_invalid_string() { + let example = r#"{"data_size": {size:10, in:8}}"#; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), MAP_TYPE_ERROR); + } +} + +#[test] +fn test_numeric_with_shellexpand_integer() { + let example = r#"{ "value": 42 }"#; + let deserialized: NumericEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.value, 42); +} + +#[test] +fn test_numeric_with_shellexpand_string() { + let example = r#"{ "value": "100" }"#; + let deserialized: NumericEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.value, 100); +} + +#[test] +fn test_numeric_with_shellexpand_invalid_string() { + let example = r#"{ "value": {size:10, in:8} }"#; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), MAP_TYPE_ERROR); + } +} + +#[test] +fn test_optional_numeric_with_shellexpand_integer() { + let example = r#"{ "optional_value": 42 }"#; + let deserialized: OptionalNumericEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.optional_value, Some(42)); +} + +#[test] +fn test_optional_numeric_with_shellexpand_string() { + let example = r#"{ "optional_value": "100" }"#; + let deserialized: OptionalNumericEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.optional_value, Some(100)); +} + +#[test] +fn test_optional_numeric_with_shellexpand_empty_string() { + let example = r#"{"optional_value": ""}"#; + let deserialized: OptionalNumericEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.optional_value, None); +} + +#[test] +fn test_optional_numeric_with_shellexpand_invalid_string() { + let example = r#"{ "optional_value": {size:10, in:8} }"#; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), MAP_TYPE_ERROR); + } +} + +#[test] +fn test_convert_string_with_shellexpand_invalid() { + let example = STRING_ENV_VAR; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), INVALID_ENV_VAR_ERROR); + } +} + +#[test] +fn test_convert_string_with_shellexpand_empty() { + let example = EMPTY_STRING_ENV_VAR; + let deserialized: StringEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.expanded_string, ""); +} + +#[test] +fn test_convert_vec_string_with_shellexpand_empty() { + let example = VEC_STRING_EMPTY; + let deserialized: VecStringEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.expanded_strings, Vec::::new()); +} + +#[test] +fn test_convert_vec_string_with_shellexpand_invalid() { + let example = r#"{"expanded_strings": ["$INVALID_ENV_VAR", "$ANOTHER_MISSING_VAR"]}"#; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), INVALID_ENV_VAR_ERROR); + } +} + +#[test] +fn test_convert_vec_string_with_shellexpand_invalid_alternate() { + let example = r#"{"expanded_strings": ["config.json", "$INVALID_ENV_VAR"]}"#; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), INVALID_ENV_VAR_ERROR); + } +} + +#[test] +fn test_convert_optional_string_with_shellexpand_none() { + let example = NULL_STRING_ENV_VAR; + let deserialized: OptionalStringEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.expanded_string, None); +} + +#[test] +fn test_convert_optional_string_with_shellexpand_empty() { + let example = EMPTY_STRING_ENV_VAR; + let deserialized: OptionalStringEntity = serde_json5::from_str(example).unwrap(); + assert_eq!(deserialized.expanded_string, Some(String::new())); +} + +#[test] +fn test_convert_optional_string_with_shellexpand_invalid() { + let example = STRING_ENV_VAR; + let result: Result = serde_json5::from_str(example); + assert!(result.is_err()); + if let Err(e) = result { + assert_eq!(e.to_string(), INVALID_ENV_VAR_ERROR); + } +} diff --git a/nativelink-error/Cargo.toml b/nativelink-error/Cargo.toml index bcbe76e9c..e624ff7be 100644 --- a/nativelink-error/Cargo.toml +++ b/nativelink-error/Cargo.toml @@ -4,7 +4,7 @@ version = "0.5.3" edition = "2021" autobins = false autoexamples = false -autotests = false +autotests = true autobenches = false [dependencies] @@ -14,8 +14,8 @@ fred = { version = "9.2.1", default-features = false, features = [ "enable-rustls-ring", ] } hex = { version = "0.4.3", default-features = false } -prost = { version = "0.13.3", default-features = false } +prost = { version = "0.13.3", features = ["std"], default-features = false } prost-types = { version = "0.13.3", default-features = false } -serde = { version = "1.0.210", default-features = false } +serde = { version = "1.0.210", features = ["derive"], default-features = false } tokio = { version = "1.40.0", features = ["fs", "rt-multi-thread", "signal", "io-util"], default-features = false } -tonic = { version = "0.12.3", features = ["transport", "tls"], default-features = false } +tonic = { version = "0.12.3", features = ["transport"], default-features = false } diff --git a/nativelink-error/tests/lib_test.rs b/nativelink-error/tests/lib_test.rs new file mode 100644 index 000000000..d46fac3f3 --- /dev/null +++ b/nativelink-error/tests/lib_test.rs @@ -0,0 +1,450 @@ +// Copyright 2024 The NativeLink Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::borrow::Cow; +use std::io; +use std::num::{ParseIntError, TryFromIntError}; + +use fred::error::{RedisError, RedisErrorKind}; +use hex::FromHexError; +use nativelink_error::{make_err, make_input_err, Code, Error, ResultExt}; +use nativelink_metric::{MetricFieldData, MetricKind, MetricsComponent}; +use nativelink_proto::google::rpc::Status; +use serde::de::Error as DeError; +use serde::ser::Error as SerError; +use tonic::{Code as TonicCode, Status as TonicStatus}; + +#[test] +fn test_serde_serialization_error_custom() { + let error = ::custom("Serialization failed due to invalid input"); + assert_eq!(error.code, Code::InvalidArgument); + assert_eq!( + error.messages, + vec!["Serialization failed due to invalid input".to_string()] + ); +} + +#[test] +fn test_serde_deserialization_error_custom() { + let error = ::custom("Deserialization failed due to corrupted data"); + assert_eq!(error.code, Code::InvalidArgument); + assert_eq!( + error.messages, + vec!["Deserialization failed due to corrupted data".to_string()] + ); +} + +#[test] +fn test_err_tip_with_code_some() { + let option = Some(42); + let result: Result = + option.err_tip_with_code(|_error| (Code::Unknown, "Should not appear")); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 42); +} + +#[test] +fn test_err_tip_with_code_none() { + let option: Option = None; + let result: Result = + option.err_tip_with_code(|_error| (Code::InvalidArgument, "Missing value in option")); + assert!(result.is_err()); + let error = result.unwrap_err(); + assert_eq!(error.code, Code::InvalidArgument); + assert_eq!(error.messages, vec!["Missing value in option".to_string()]); +} +#[test] +fn test_code_to_error_conversion() { + let error: Error = Code::InvalidArgument.into(); + println!( + "Debug: Error Code - {:?}, Messages - {:?}", + error.code, error.messages + ); + assert_eq!( + error.code, + Code::InvalidArgument, + "Expected code to be InvalidArgument" + ); + assert!( + error.messages.is_empty() || error.messages[0].is_empty(), + "Expected messages to be empty or contain an empty string, but found: {:?}", + error.messages + ); +} + +#[test] +fn test_redis_error_conversion_invalid_argument() { + let redis_error = RedisError::new(RedisErrorKind::InvalidArgument, "Invalid argument error"); + let error: Error = redis_error.into(); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages[0].contains("Invalid argument error")); +} + +#[test] +fn test_redis_error_conversion_internal() { + let redis_error = RedisError::new(RedisErrorKind::IO, "Internal error"); + let error: Error = redis_error.into(); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("Internal error")); +} + +#[test] +fn test_redis_error_conversion_permission_denied() { + let redis_error = RedisError::new(RedisErrorKind::Auth, "Permission denied error"); + let error: Error = redis_error.into(); + assert_eq!(error.code, Code::PermissionDenied); + assert!(error.messages[0].contains("Permission denied error")); +} + +#[test] +fn test_redis_error_conversion_timeout() { + let redis_error = RedisError::new(RedisErrorKind::Timeout, "Timeout error"); + let error: Error = redis_error.into(); + assert_eq!(error.code, Code::DeadlineExceeded); + assert!(error.messages[0].contains("Timeout error")); +} + +#[test] +fn test_transport_error_conversion_simulation() { + let error: Error = make_err!(Code::Internal, "Transport connection failed simulation"); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("Transport connection failed simulation")); +} + +#[test] +fn test_transport_error_simulation() { + let error: Error = make_err!(Code::Internal, "Transport connection failed simulation"); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("Transport connection failed simulation")); +} + +#[test] +fn test_status_to_error_conversion_unique() { + let tonic_status = TonicStatus::invalid_argument("Invalid argument provided"); + let error: Error = tonic_status.into(); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages[0].contains("Invalid argument provided")); +} + +#[test] +fn test_error_to_status_conversion() { + let error = Error { + code: Code::Internal, + messages: vec!["An internal error occurred".to_string()], + }; + let tonic_status: TonicStatus = error.into(); + assert_eq!(tonic_status.code(), TonicCode::Internal); + assert!(tonic_status + .message() + .contains("An internal error occurred")); +} + +#[test] +fn test_encode_error_conversion() { + let error: Error = make_err!(Code::Internal, "Encode failure mock"); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("Encode failure mock")); +} + +#[test] +fn test_try_from_int_error_conversion() { + let int_error: Result = u16::try_into(300); + let error: Error = int_error.unwrap_err().into(); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages[0].contains("out of range")); +} + +#[test] +fn test_parse_int_error_conversion() { + let parse_error: Result = "abc".parse(); + let error: Error = parse_error.unwrap_err().into(); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages[0].contains("invalid digit")); +} + +#[test] +fn test_from_hex_error_conversion() { + let hex_error = FromHexError::InvalidStringLength; + let error: Error = hex_error.into(); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages[0].contains("Invalid string length")); +} + +#[tokio::test] +async fn test_join_error_conversion() { + let join_error = tokio::spawn(async { panic!("JoinError mock") }) + .await + .unwrap_err(); + let error: Error = join_error.into(); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("JoinError mock")); +} + +#[test] +fn test_prost_encode_error_conversion() { + let error = make_err!(Code::Internal, "Encode failure mock"); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("Encode failure mock")); +} + +#[test] +fn test_prost_unknown_enum_value_conversion() { + let error = make_err!(Code::Internal, "Unknown enum value mock"); + assert_eq!(error.code, Code::Internal); + assert!(error.messages[0].contains("Unknown enum value mock")); +} + +#[test] +fn test_timestamp_error_conversion() { + let error = make_err!(Code::InvalidArgument, "Timestamp error mock"); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages[0].contains("Timestamp error mock")); +} + +#[test] +fn test_status_to_error_conversion() { + let status = Status { + code: Code::InvalidArgument as i32, + message: "Test error message".to_string(), + details: vec![], + }; + let error: Error = status.into(); + assert_eq!(error.code, Code::InvalidArgument); + assert_eq!(error.messages, vec!["Test error message"]); +} + +#[test] +fn test_metrics_component_publish() { + let error = Error::new(Code::Internal, "Metrics publish error".to_string()); + let kind = MetricKind::Default; + let field_metadata = MetricFieldData { + name: Cow::from("test_metric"), + group: Cow::from("test_group"), + help: Cow::from("help message"), + }; + let result = error.publish(kind, field_metadata); + match result { + Ok(data) => { + println!("Published data: {:?}", data); + } + Err(e) => panic!("Publish failed with error: {:?}", e), + } +} + +#[test] +fn test_error_new() { + let error = Error::new(Code::Internal, "Error occurred".to_string()); + assert_eq!(error.code, Code::Internal); + assert_eq!(error.messages, vec!["Error occurred"]); +} + +#[test] +fn test_error_append() { + let error = Error::new(Code::Internal, "Initial error".to_string()).append("Additional error"); + assert_eq!(error.messages, vec!["Initial error", "Additional error"]); +} + +#[test] +fn test_error_merge() { + let error1 = Error::new(Code::Internal, "Error 1".to_string()); + let error2 = Error::new(Code::Unknown, "Error 2".to_string()); + let merged_error = error1.merge(error2); + assert_eq!(merged_error.messages, vec!["Error 1", "---", "Error 2"]); +} + +#[test] +fn test_error_merge_option() { + let error1 = Some(Error::new(Code::Internal, "Error 1".to_string())); + let error2 = Some(Error::new(Code::Unknown, "Error 2".to_string())); + let merged_error = Error::merge_option(error1, error2); + assert!(merged_error.is_some()); + assert_eq!( + merged_error.unwrap().messages, + vec!["Error 1", "---", "Error 2"] + ); +} + +#[test] +fn test_error_to_std_err() { + let error = Error::new(Code::Internal, "IO Error".to_string()); + let io_error = error.to_std_err(); + assert_eq!(io_error.kind(), io::ErrorKind::Other); + assert_eq!(io_error.to_string(), "IO Error"); +} + +#[test] +fn test_error_message_string() { + let error = Error::new(Code::Internal, "Part 1".to_string()).append("Part 2"); + assert_eq!(error.message_string(), "Part 1 : Part 2"); +} + +#[test] +fn test_error_make_err_macro() { + let error = make_err!(Code::InvalidArgument, "Invalid argument: {}", "value"); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error + .messages + .contains(&"Invalid argument: value".to_string())); +} + +#[test] +fn test_error_make_input_err_macro() { + let error = make_input_err!("Input error: {}", "example"); + assert_eq!(error.code, Code::InvalidArgument); + assert!(error.messages.contains(&"Input error: example".to_string())); +} + +#[test] +fn test_error_conversion_from_prost_decode_error() { + let prost_error = prost::DecodeError::new("Decode failure"); + let error: Error = prost_error.into(); + assert_eq!(error.code, Code::Internal); + assert!( + error.messages[0].contains("Decode failure"), + "Error message was: {:?}", + error.messages + ); +} + +#[test] +fn test_error_conversion_from_std_io_error() { + let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found"); + let error: Error = io_error.into(); + assert_eq!(error.code, Code::NotFound); + assert!(error.messages.contains(&"File not found".to_string())); +} + +#[test] +fn test_result_ext_err_tip() { + let result: Result<(), Error> = + Err(Error::new(Code::Internal, "Base error".to_string())).err_tip(|| "Additional context"); + let error = result.unwrap_err(); + assert!(error.messages.contains(&"Additional context".to_string())); +} + +#[test] +fn test_result_ext_merge() { + let result1: Result<(), Error> = Err(Error::new(Code::Internal, "First error".to_string())); + let result2: Result<(), Error> = Err(Error::new(Code::Unknown, "Second error".to_string())); + let merged_result = result1.merge(result2); + let error = merged_result.unwrap_err(); + assert_eq!(error.messages, vec!["First error", "---", "Second error"]); +} + +#[test] +fn test_tonic_code_to_code_conversion() { + assert_eq!(Code::from(TonicCode::Ok), Code::Ok); + assert_eq!(Code::from(TonicCode::Cancelled), Code::Cancelled); + assert_eq!(Code::from(TonicCode::Unknown), Code::Unknown); + assert_eq!( + Code::from(TonicCode::InvalidArgument), + Code::InvalidArgument + ); + assert_eq!( + Code::from(TonicCode::DeadlineExceeded), + Code::DeadlineExceeded + ); + assert_eq!(Code::from(TonicCode::NotFound), Code::NotFound); + assert_eq!(Code::from(TonicCode::AlreadyExists), Code::AlreadyExists); + assert_eq!( + Code::from(TonicCode::PermissionDenied), + Code::PermissionDenied + ); + assert_eq!( + Code::from(TonicCode::ResourceExhausted), + Code::ResourceExhausted + ); + assert_eq!( + Code::from(TonicCode::FailedPrecondition), + Code::FailedPrecondition + ); + assert_eq!(Code::from(TonicCode::Aborted), Code::Aborted); + assert_eq!(Code::from(TonicCode::OutOfRange), Code::OutOfRange); + assert_eq!(Code::from(TonicCode::Unimplemented), Code::Unimplemented); + assert_eq!(Code::from(TonicCode::Internal), Code::Internal); + assert_eq!(Code::from(TonicCode::Unavailable), Code::Unavailable); + assert_eq!(Code::from(TonicCode::DataLoss), Code::DataLoss); + assert_eq!( + Code::from(TonicCode::Unauthenticated), + Code::Unauthenticated + ); +} + +#[test] +fn test_code_to_tonic_code_conversion() { + assert_eq!(TonicCode::from(Code::Ok), TonicCode::Ok); + assert_eq!(TonicCode::from(Code::Cancelled), TonicCode::Cancelled); + assert_eq!(TonicCode::from(Code::Unknown), TonicCode::Unknown); + assert_eq!( + TonicCode::from(Code::InvalidArgument), + TonicCode::InvalidArgument + ); + assert_eq!( + TonicCode::from(Code::DeadlineExceeded), + TonicCode::DeadlineExceeded + ); + assert_eq!(TonicCode::from(Code::NotFound), TonicCode::NotFound); + assert_eq!( + TonicCode::from(Code::AlreadyExists), + TonicCode::AlreadyExists + ); + assert_eq!( + TonicCode::from(Code::PermissionDenied), + TonicCode::PermissionDenied + ); + assert_eq!( + TonicCode::from(Code::ResourceExhausted), + TonicCode::ResourceExhausted + ); + assert_eq!( + TonicCode::from(Code::FailedPrecondition), + TonicCode::FailedPrecondition + ); + assert_eq!(TonicCode::from(Code::Aborted), TonicCode::Aborted); + assert_eq!(TonicCode::from(Code::OutOfRange), TonicCode::OutOfRange); + assert_eq!( + TonicCode::from(Code::Unimplemented), + TonicCode::Unimplemented + ); + assert_eq!(TonicCode::from(Code::Internal), TonicCode::Internal); + assert_eq!(TonicCode::from(Code::Unavailable), TonicCode::Unavailable); + assert_eq!(TonicCode::from(Code::DataLoss), TonicCode::DataLoss); + assert_eq!( + TonicCode::from(Code::Unauthenticated), + TonicCode::Unauthenticated + ); +} + +#[test] +fn test_i32_to_code_conversion() { + assert_eq!(Code::from(0), Code::Ok); + assert_eq!(Code::from(1), Code::Cancelled); + assert_eq!(Code::from(2), Code::Unknown); + assert_eq!(Code::from(3), Code::InvalidArgument); + assert_eq!(Code::from(4), Code::DeadlineExceeded); + assert_eq!(Code::from(5), Code::NotFound); + assert_eq!(Code::from(6), Code::AlreadyExists); + assert_eq!(Code::from(7), Code::PermissionDenied); + assert_eq!(Code::from(8), Code::ResourceExhausted); + assert_eq!(Code::from(9), Code::FailedPrecondition); + assert_eq!(Code::from(10), Code::Aborted); + assert_eq!(Code::from(11), Code::OutOfRange); + assert_eq!(Code::from(12), Code::Unimplemented); + assert_eq!(Code::from(13), Code::Internal); + assert_eq!(Code::from(14), Code::Unavailable); + assert_eq!(Code::from(15), Code::DataLoss); + assert_eq!(Code::from(16), Code::Unauthenticated); + assert_eq!(Code::from(99), Code::Unknown); + assert_eq!(Code::from(-1), Code::Unknown); +} diff --git a/nativelink-metric-collector/src/lib.rs b/nativelink-metric-collector/src/lib.rs index 9316abdc6..894276b28 100644 --- a/nativelink-metric-collector/src/lib.rs +++ b/nativelink-metric-collector/src/lib.rs @@ -16,6 +16,6 @@ pub use otel_exporter::otel_export; pub use tracing_layers::MetricsCollectorLayer; mod metrics_collection; -mod metrics_visitors; +pub mod metrics_visitors; mod otel_exporter; mod tracing_layers;