From e332df0a37e6a0486c2f925c92865d02476f057d Mon Sep 17 00:00:00 2001 From: puffyCid <16283453+puffyCid@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:22:57 -0500 Subject: [PATCH 1/3] added test files --- .github/workflows/pullrequest.yml | 2 +- .gitignore | 4 +- tests/big_sur_tests.rs | 804 ++++++++++++++++++++++++++++++ tests/high_sierra_tests.rs | 329 ++++++++++++ tests/monterey_tests.rs | 221 ++++++++ 5 files changed, 1357 insertions(+), 3 deletions(-) create mode 100755 tests/big_sur_tests.rs create mode 100755 tests/high_sierra_tests.rs create mode 100755 tests/monterey_tests.rs diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 3e8b58c..22547b1 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -41,7 +41,7 @@ jobs: run: cargo clippy - name: Download test files - run: wget -O ./tests.zip https://github.com/mandiant/macos-UnifiedLogs/releases/download/v1.0.0/tests.zip && unzip tests.zip + run: cd tests && wget -O ./test_data.zip https://github.com/mandiant/macos-UnifiedLogs/releases/download/v1.0.0/test_data.zip && unzip test_data.zip - name: Build tests run: cargo test --no-run --release - name: Run tests diff --git a/.gitignore b/.gitignore index 098a8db..6fa2a81 100755 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,5 @@ Cargo.lock *.DS_Store *.logarchive -tests.zip -tests/ \ No newline at end of file +test*.zip +tests/test_data \ No newline at end of file diff --git a/tests/big_sur_tests.rs b/tests/big_sur_tests.rs new file mode 100755 index 0000000..c2aa83b --- /dev/null +++ b/tests/big_sur_tests.rs @@ -0,0 +1,804 @@ +// Copyright 2022 Mandiant, Inc. 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::{fs, path::PathBuf}; + +use macos_unifiedlogs::{ + parser::{build_log, collect_shared_strings, collect_strings, collect_timesync, parse_log}, + unified_log::{LogData, UnifiedLogData}, +}; +use regex::Regex; + +fn collect_logs(path: &str) -> Vec { + let paths = fs::read_dir(path).unwrap(); + + let mut log_data_vec: Vec = Vec::new(); + for path in paths { + let data = path.unwrap(); + let full_path = data.path().display().to_string(); + let log_data = parse_log(&full_path).unwrap(); + log_data_vec.push(log_data); + } + + return log_data_vec; +} + +#[test] +fn test_parse_log_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + + test_path.push("Persist/0000000000000004.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + assert_eq!(log_data.catalog_data[0].firehose.len(), 82); + assert_eq!(log_data.catalog_data[0].simpledump.len(), 0); + assert_eq!(log_data.header.len(), 1); + assert_eq!( + log_data.catalog_data[0] + .catalog + .catalog_process_info_entries + .len(), + 45 + ); + assert_eq!(log_data.catalog_data[0].statedump.len(), 0); +} + +#[test] +fn test_big_sur_livedata() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + let exclude_missing = false; + let (data, _) = build_log( + &results, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(data.len(), 101566); + + for results in data { + // Test for a log message that uses a firehose_header_timestamp with a value of zero + if results.message == "TimeSyncTime is mach_absolute_time nanoseconds\n" { + assert_eq!( + results.message, + "TimeSyncTime is mach_absolute_time nanoseconds\n" + ); + assert_eq!(results.activity_id, 0); + assert_eq!(results.thread_id, 116); + assert_eq!(results.euid, 0); + assert_eq!(results.pid, 0); + assert_eq!( + results.library, + "/System/Library/Extensions/IOTimeSyncFamily.kext/Contents/MacOS/IOTimeSyncFamily" + ); + assert_eq!(results.subsystem, String::new()); + assert_eq!(results.category, String::new()); + assert_eq!(results.event_type, "Log"); + assert_eq!(results.log_type, "Info"); + assert_eq!(results.process, "/kernel"); + assert_eq!(results.time, 1642304801596413351.0); + assert_eq!(results.boot_uuid, "A2A9017676CF421C84DC9BBD6263FEE7"); + assert_eq!(results.timezone_name, "Pacific"); + } + } +} + +#[test] +fn test_build_log_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000004.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 110953); + assert_eq!(results[0].process, "/usr/libexec/opendirectoryd"); + assert_eq!(results[0].subsystem, "com.apple.opendirectoryd"); + assert_eq!(results[0].time, 1642303933964503310.0); + assert_eq!(results[0].activity_id, 0); + assert_eq!(results[0].library, "/usr/libexec/opendirectoryd"); + assert_eq!( + results[0].message, + "opendirectoryd (build 796.100) launched..." + ); + assert_eq!(results[0].pid, 105); + assert_eq!(results[0].thread_id, 670); + assert_eq!(results[0].category, "default"); + assert_eq!(results[0].log_type, "Default"); + assert_eq!(results[0].event_type, "Log"); + assert_eq!(results[0].euid, 0); + assert_eq!(results[0].boot_uuid, "AACFB573E87545CE98B893D132766A46"); + assert_eq!(results[0].timezone_name, "Pacific"); + assert_eq!(results[0].library_uuid, "B736DF1625F538248E9527A8CEC4991E"); + assert_eq!(results[0].process_uuid, "B736DF1625F538248E9527A8CEC4991E"); + assert_eq!( + results[0].raw_message, + "opendirectoryd (build %{public}s) launched..." + ); +} + +#[test] +fn test_parse_all_logs_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist"); + + let mut log_data = collect_logs(&test_path.display().to_string()); + test_path.pop(); + + test_path.push("HighVolume"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Special"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Signpost"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + log_data.push(results); + test_path.pop(); + + let mut log_data_vec: Vec = Vec::new(); + let exclude_missing = false; + for logs in &log_data { + let (mut data, _) = build_log( + &logs, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + log_data_vec.append(&mut data); + } + // Run: "log raw-dump -a macos-unifiedlogs/tests/test_data/system_logs_big_sur.logarchive" + // total log entries: 747,294 + // Add Statedump log entries: 322 + // Total log entries: 747,616 + assert_eq!(log_data_vec.len(), 747616); + + let mut unknown_strings = 0; + let mut invalid_offsets = 0; + let mut invalid_shared_string_offsets = 0; + let mut statedump_custom_objects = 0; + let mut statedump_protocol_buffer = 0; + + let mut found_precision_string = false; + let mut statedump_count = 0; + let mut signpost_count = 0; + + let mut default_type = 0; + let mut info_type = 0; + let mut error_type = 0; + let mut create_type = 0; + let mut debug_type = 0; + let mut useraction_type = 0; + let mut fault_type = 0; + let mut loss_type = 0; + + let mut string_count = 0; + let message_re = Regex::new(r"^[\s]*%s\s*$").unwrap(); + let mut empty_format_count = 0; + let mut sock_count = 0; + + // Breakdown log entries by smaller types to ensure count is accurate + for logs in &log_data_vec { + if logs.message.contains("Failed to get string message from ") + || logs.message.contains("Unknown shared string message") + { + unknown_strings += 1; + } else if logs.message.contains("Error: Invalid offset ") { + invalid_offsets += 1; + } else if logs.message.contains("Error: Invalid shared string offset") { + invalid_shared_string_offsets += 1; + } else if logs.message.contains("Unsupported Statedump object") { + statedump_custom_objects += 1; + } else if logs.message.contains("Statedump Protocol Buffer") { + statedump_protocol_buffer += 1; + } else if logs.message + == r##"#32EC4B64 [AssetCacheLocatorService.queue] sending POST [327]{"locator-tag":"#32ec4b64","local-addresses":["192.168.101.144"],"ranked-results":true,"locator-software":[{"build":"20G224","type":"system","name":"macOS","version":"11.6.1"},{"id":"com.apple.AssetCacheLocatorService","executable":"AssetCacheLocatorService","type":"bundle","name":"AssetCacheLocatorService","version":"118"}]} to https://lcdn-locator.apple.com/lcdn/locate"## + { + found_precision_string = true; + } + + if logs.event_type == "Statedump" { + statedump_count += 1; + } else if logs.event_type == "Signpost" { + signpost_count += 1; + } else if logs.log_type == "Default" { + default_type += 1; + } else if logs.log_type == "Info" { + info_type += 1; + } else if logs.log_type == "Error" { + error_type += 1 + } else if logs.log_type == "Create" { + create_type += 1; + } else if logs.log_type == "Debug" { + debug_type += 1; + } else if logs.log_type == "Useraction" { + useraction_type += 1; + } else if logs.log_type == "Fault" { + fault_type += 1; + } else if logs.event_type == "Loss" { + loss_type += 1; + } + + if message_re.is_match(&logs.raw_message) { + string_count += 1; + } + + if logs.raw_message.is_empty() && logs.message.is_empty() && logs.event_type != "Loss" { + empty_format_count += 1 + } + + if logs.message.contains("nw_resolver_create_dns_getaddrinfo_locked_block_invoke [C1] Got DNS result type NoAddress ifindex=0 configuration.ls.apple.com configuration.ls.apple.com. ::") { + sock_count += 1; + } + } + + assert_eq!(unknown_strings, 0); + assert_eq!(invalid_offsets, 54); + assert_eq!(invalid_shared_string_offsets, 0); + assert_eq!(statedump_custom_objects, 2); + assert_eq!(statedump_protocol_buffer, 3); + assert_eq!(found_precision_string, true); + + assert_eq!(statedump_count, 322); + assert_eq!(signpost_count, 50665); + assert_eq!(string_count, 11764); + assert_eq!(empty_format_count, 56); + assert_eq!(default_type, 462518); + assert_eq!(info_type, 114540); + assert_eq!(error_type, 29132); + assert_eq!(create_type, 87831); + assert_eq!(debug_type, 1908); + assert_eq!(useraction_type, 15); + assert_eq!(fault_type, 680); + assert_eq!(loss_type, 5); + assert_eq!(sock_count, 2); +} + +#[test] +fn test_parse_all_persist_logs_with_network_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist"); + + let mut log_data = collect_logs(&test_path.display().to_string()); + test_path.pop(); + + test_path.push("HighVolume"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Special"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + log_data.push(results); + test_path.pop(); + + let mut log_data_vec: Vec = Vec::new(); + let exclude_missing = false; + + for logs in &log_data { + let (mut data, _) = build_log( + &logs, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + log_data_vec.append(&mut data); + } + + let mut messages_containing_network = 0; + let mut default_type = 0; + let mut info_type = 0; + let mut error_type = 0; + let mut create_type = 0; + let mut state_simple_dump = 0; + let mut signpost = 0; + + let mut network_message_uuid = false; + + // Check all logs that contain the word "network" + for logs in &log_data_vec { + if logs.message.to_lowercase().contains("network") { + if logs.log_type == "Default" { + default_type += 1; + if logs + .message + .contains("7C10C1EF-1B86-494F-800D-C769A89172C1") + { + // The Console.app does not show the following network message. This might be a bug in the app? + // But the log command shows it correctly + // This is the only message that contains the UUID 7C10C1EF-1B86-494F-800D-C769A89172C1 + /* + tp 2264 + 286: log default (has_current_aid, shared_cache, has_subsystem) + thread: 00000000000036ea + time: +95.856s + walltime: 1648611808 - 2022-03-29 20:43:28 (Tuesday) + cur_aid: 8000000000007840 + location: pc:0x405faf5 fmt:0x4613cd0 + image uuid: 6D702F3B-34C0-3809-8CEC-1D59D58CF8BB + image path: /usr/lib/libnetwork.dylib + format: [C%u %{public,uuid_t}.16P %{public}s %{public}s] start + subsystem: 50 com.apple.network.connection + [C6 527C4884-E24B-425C-B3AB-AA91DCD23FCE configuration.ls.apple.com:443 tcp, url hash: 8feb6d24, tls, context: com.apple.CFNetwork.NSURLSession.{7C10C1EF-1B86-494F-800D-C769A89172C1}{(null)}{Y}{1}, proc: 21B380F4-D50C-3463-9CAF-46BB2178258B] start + */ + network_message_uuid = true; + } + } else if logs.log_type == "Info" { + info_type += 1; + } else if logs.log_type == "Error" { + error_type += 1 + } else if logs.log_type == "Create" { + create_type += 1; + // We are basing these counts on the Cosole.app tool + // Console.app skips Activity event logs + continue; + } else if logs.log_type == String::new() { + // We are basing these counts on the Cosole.app tool + // Console.app skips Simple and State dump event logs + state_simple_dump += 1; + continue; + } else if logs.log_type.contains("Signpost") { + // We are basing these counts on the Cosole.app tool + // Console.app skips Signpost event logs + signpost += 1; + continue; + } + messages_containing_network += 1; + } + } + assert_eq!(messages_containing_network, 9173); + // Console.app is missing a log entry. The log command shows the entry + assert_eq!(default_type, 8320); + assert_eq!(network_message_uuid, true); + + assert_eq!(info_type, 638); + assert_eq!(error_type, 215); + assert_eq!(create_type, 687); + assert_eq!(state_simple_dump, 34); + assert_eq!(signpost, 37); +} + +#[test] +fn test_parse_all_logs_private_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur_private_enabled.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist"); + + let mut log_data = collect_logs(&test_path.display().to_string()); + test_path.pop(); + + test_path.push("HighVolume"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Special"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Signpost"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + log_data.push(results); + test_path.pop(); + + let mut log_data_vec: Vec = Vec::new(); + let exclude_missing = false; + for logs in &log_data { + let (mut data, _) = build_log( + &logs, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + log_data_vec.append(&mut data); + } + assert_eq!(log_data_vec.len(), 887890); + + let mut empty_counter = 0; + let mut not_found = 0; + let mut staff_count = 0; + for logs in log_data_vec { + if logs.message == "" { + empty_counter += 1; + } + if logs.message.contains("") { + println!("{}", logs.message); + not_found += 1; + } + if logs.message.contains("group: staff@/Local/Default") { + staff_count += 1; + } + } + assert_eq!(not_found, 0); + assert_eq!(staff_count, 4); + assert_eq!(empty_counter, 596); +} + +// Test for logs that have same public data in private +#[test] +fn test_parse_all_logs_private_with_public_mix_big_sur() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur_public_private_data_mix.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist"); + + let mut log_data = collect_logs(&test_path.display().to_string()); + test_path.pop(); + + test_path.push("HighVolume"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Special"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Signpost"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + log_data.push(results); + test_path.pop(); + + let mut log_data_vec: Vec = Vec::new(); + let exclude_missing = false; + + for logs in &log_data { + let (mut data, _) = build_log( + &logs, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + log_data_vec.append(&mut data); + } + assert_eq!(log_data_vec.len(), 1287628); + + let mut not_found = 0; + let mut user_not_found = 0; + let mut mobile_not_found = 0; + let mut bssid_count = 0; + let mut dns_query_count = 0; + let mut bofa_count = 0; + + for logs in log_data_vec { + if logs.message.contains("") { + not_found += 1; + } + if logs.message.contains("user: -1 ") { + user_not_found += 1; + } + + if logs.message.contains("refreshing: details, reason: expired, user: mobile ") { + mobile_not_found += 1; + } + + if logs.message.contains("BSSID 00:00:00:00:00:00") { + bssid_count += 1; + } + + if logs.message.contains("https://doh.dns.apple.com/dns-query") { + dns_query_count += 1; + } + + if logs.message.contains("bankofamerica") { + bofa_count += 1; + } + } + assert_eq!(not_found, 5); + assert_eq!(user_not_found, 2); + assert_eq!(mobile_not_found, 1); + assert_eq!(bssid_count, 39); + assert_eq!(dns_query_count, 41); + assert_eq!(bofa_count, 573); +} + +#[test] +fn test_parse_all_logs_private_with_public_mix_big_sur_single_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur_public_private_data_mix.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000009.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 91567); + + let mut hex_count = 0; + let mut dns = 0; + let mut public_private_mixture = false; + for result in results { + if result.message.contains("7FAE25804F50") { + hex_count += 1; + } + if result.subsystem.contains(".mdns") { + dns += 1; + } + // 7FAE25B0E420 is half public and half private + // B0E420 exists in public data but is copied/prepended to the private data. + // 7FAE25 only exists in private data + if result.message + == "os_transaction created: (7FAE25B0E420) CLLS:0x7fae23628160.LocationFine" + { + public_private_mixture = true + } + } + + assert_eq!(hex_count, 4); + assert_eq!(dns, 801); + assert_eq!(public_private_mixture, true); +} + +// We are able to get 2238 entries from this special tracev3 file. But log command only gets 231 +#[test] +fn test_parse_all_logs_private_with_public_mix_big_sur_special_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur_public_private_data_mix.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Special/0000000000000008.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 2238); + + let mut statedump = 0; + let mut default = 0; + let mut fault = 0; + let mut info = 0; + let mut error = 0; + + for result in results { + if result.event_type == "Statedump" { + statedump += 1; + } else if result.log_type == "Default" { + default += 1; + } else if result.log_type == "Fault" { + fault += 1; + } else if result.log_type == "Info" { + info += 1; + } else if result.log_type == "Error" { + error += 1; + } + } + + assert_eq!(statedump, 1); + assert_eq!(default, 1972); + assert_eq!(fault, 32); + assert_eq!(info, 41); + assert_eq!(error, 192); +} + +#[test] +fn test_big_sur_missing_oversize_strings() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + // livedata may have oversize string data in other tracev3 on disk + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + let exclude_missing = false; + let (data, _) = build_log( + &results, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(data.len(), 101566); + + let mut missing_strings = 0; + for results in data { + if results.message.contains("") { + missing_strings = missing_strings + 1; + } + } + // There should be only 29 entries that have actual missing data + // 23 strings are in other trave3 files. 23 + 29 = 52 + assert_eq!(missing_strings, 52); +} + +#[test] +fn test_big_sur_oversize_strings_in_another_file() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_big_sur.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + // Get most recent Persist tracev3 file could contain oversize log entries + test_path.push("Persist/0000000000000005.tracev3"); + let mut log_data = parse_log(&test_path.display().to_string()).unwrap(); + test_path.pop(); + test_path.pop(); + + // Get most recent Special tracev3 file that could contain oversize log entries + test_path.push("Special/0000000000000005.tracev3"); + let mut special_data = parse_log(&test_path.display().to_string()).unwrap(); + test_path.pop(); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let mut results = parse_log(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + results.oversize.append(&mut log_data.oversize); + results.oversize.append(&mut special_data.oversize); + + let exclude_missing = false; + let (data, _) = build_log( + &results, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(data.len(), 101566); + + let mut missing_strings = 0; + for results in data { + if results.message.contains("") { + missing_strings = missing_strings + 1; + } + } + // 29 log entries actually have missing data + // Apple displays as: + assert_eq!(missing_strings, 29); +} diff --git a/tests/high_sierra_tests.rs b/tests/high_sierra_tests.rs new file mode 100755 index 0000000..8ffc50c --- /dev/null +++ b/tests/high_sierra_tests.rs @@ -0,0 +1,329 @@ +// Copyright 2022 Mandiant, Inc. 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::{fs, path::PathBuf}; + +use macos_unifiedlogs::{ + parser::{build_log, collect_shared_strings, collect_strings, collect_timesync, parse_log}, + unified_log::{LogData, UnifiedLogData}, +}; +use regex::Regex; + +fn collect_logs(path: &str) -> Vec { + let paths = fs::read_dir(path).unwrap(); + + let mut log_data_vec: Vec = Vec::new(); + for path in paths { + let data = path.unwrap(); + let full_path = data.path().display().to_string(); + let log_data = parse_log(&full_path).unwrap(); + log_data_vec.push(log_data); + } + + return log_data_vec; +} + +#[test] +fn test_parse_log_high_sierra() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + + test_path.push("Persist/0000000000000001.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + assert_eq!(log_data.catalog_data[0].firehose.len(), 172); + assert_eq!(log_data.catalog_data[0].simpledump.len(), 0); + assert_eq!(log_data.header.len(), 1); + assert_eq!( + log_data.catalog_data[0] + .catalog + .catalog_process_info_entries + .len(), + 30 + ); + assert_eq!(log_data.catalog_data[0].statedump.len(), 0); +} + +#[test] +fn test_build_log_high_sierra() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000001.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 162402); + assert_eq!(results[0].process, "/usr/libexec/opendirectoryd"); + assert_eq!(results[0].subsystem, "com.apple.opendirectoryd"); + assert_eq!(results[0].time, 1624134811546060433.0); + assert_eq!(results[0].activity_id, 0); + assert_eq!(results[0].library, "/usr/libexec/opendirectoryd"); + assert_eq!( + results[0].message, + "opendirectoryd (build 483.700) launched..." + ); + assert_eq!(results[0].pid, 59); + assert_eq!(results[0].thread_id, 622); + assert_eq!(results[0].category, "default"); + assert_eq!(results[0].log_type, "Default"); + assert_eq!(results[0].event_type, "Log"); + assert_eq!(results[0].euid, 0); + assert_eq!(results[0].boot_uuid, "30774817CF1549B0920E1A8E17D47AB5"); + assert_eq!(results[0].timezone_name, "Pacific"); + assert_eq!(results[0].process_uuid, "AD43C574A9F73311A4E995237667082A"); + assert_eq!(results[0].library_uuid, "AD43C574A9F73311A4E995237667082A"); + assert_eq!( + results[0].raw_message, + "opendirectoryd (build %{public}s) launched..." + ); +} +#[test] +fn test_build_log_complex_format_high_sierra() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/0000000000000001.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 162402); + + for result in &results { + if result.message == " Calculated minimum fire date [2021-06-19 19:47:59 -0700] (75%) with fire date [2021-06-19 21:51:14 -0700], start date [2021-06-19 13:38:14 -0700], minimum early fire proportion 0.75, power state detection supported: no, in high power state: no, early fire constant interval 0" { + assert_eq!(result.process, "/System/Library/PrivateFrameworks/CalendarNotification.framework/Versions/A/XPCServices/CalNCService.xpc/Contents/MacOS/CalNCService"); + assert_eq!(result.subsystem, "com.apple.PersistentConnection"); + assert_eq!(result.time,1624135094694359040.0); + assert_eq!(result.activity_id, 0); + assert_eq!(result.library, "/System/Library/PrivateFrameworks/PersistentConnection.framework/Versions/A/PersistentConnection"); + assert_eq!( + result.message, + " Calculated minimum fire date [2021-06-19 19:47:59 -0700] (75%) with fire date [2021-06-19 21:51:14 -0700], start date [2021-06-19 13:38:14 -0700], minimum early fire proportion 0.75, power state detection supported: no, in high power state: no, early fire constant interval 0" + ); + assert_eq!(result.pid, 580); + assert_eq!(result.thread_id, 8759); + assert_eq!(result.category, "persistentTimer.com.apple.CalendarNotification.EKTravelEngine.periodicRefreshTimer"); + assert_eq!(result.log_type, "Default"); + assert_eq!(result.event_type, "Log"); + assert_eq!(result.euid, 501); + assert_eq!(result.boot_uuid, "30774817CF1549B0920E1A8E17D47AB5"); + assert_eq!(result.timezone_name, "Pacific"); + assert_eq!(result.process_uuid, "3E78A65047873F8AAFB10EA606B84B5D"); + assert_eq!(result.library_uuid, "761AF71A7FBE3374A4A48A38E0D59B6B"); + assert_eq!(result.raw_message, "%{public}@ Calculated minimum fire date [%{public}@] (%g%%) with fire date [%{public}@], start date [%{public}@], minimum early fire proportion %g, power state detection supported: %{public}s, in high power state: %{public}s, early fire constant interval %f"); + return + } + } + panic!("Did not find message match") +} + +#[test] +fn test_build_log_negative_number_high_sierra() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Special/0000000000000003.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 12058); + + for result in &results { + if result.message + == "[BTUserEventAgentController messageTracerEventDriven] PowerSource -2 -2\n" + { + assert_eq!( + result.raw_message, + "[BTUserEventAgentController messageTracerEventDriven] PowerSource %f %f\n" + ); + return; + } + } + panic!("Did not find negative message match") +} + +#[test] +fn test_parse_all_logs_high_sierra() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_high_sierra.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist"); + + let mut log_data = collect_logs(&test_path.display().to_string()); + test_path.pop(); + + test_path.push("HighVolume"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Special"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + log_data.push(results); + test_path.pop(); + + let mut log_data_vec: Vec = Vec::new(); + let exclude_missing = false; + for logs in &log_data { + let (mut data, _) = build_log( + &logs, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + log_data_vec.append(&mut data); + } + assert_eq!(log_data_vec.len(), 569796); + + let mut empty_counter = 0; + let mut empty_identityservicesd = 0; + let mut empty_callservicesd = 0; + let mut empty_configd = 0; + let mut empty_coreduetd = 0; + let mut private_entries = 0; + let mut kernel_entries = 0; + let mut string_count = 0; + + let message_re = Regex::new(r"^[\s]*%s\s*$").unwrap(); + + for logs in &log_data_vec { + if logs.message == "" { + empty_counter += 1; + + if logs.process == "/System/Library/PrivateFrameworks/TelephonyUtilities.framework/callservicesd" { + empty_callservicesd += 1; + } else if logs.process == "/System/Library/PrivateFrameworks/IDS.framework/identityservicesd.app/Contents/MacOS/identityservicesd" { + empty_identityservicesd += 1; + } else if logs.process == "/usr/libexec/configd" { + empty_configd += 1; + } else if logs.process == "/usr/libexec/coreduetd" { + empty_coreduetd += 1; + } + } else if logs.message.contains("") { + private_entries += logs.message.matches("").count(); + } + if logs.message.contains("bytes in/out: 818/542, packets in/out: 2/2, rtt: 0.020s, retransmitted packets: 1, out-of-order packets: 2") { + assert_eq!(logs.message, "[11 stream, pid: 344] cancelled\n\t[11.1 334B42D96E654481B31C3A452BFB96B7 .49154<->]\n\tConnected Path: satisfied (Path is satisfied), interface: en0, ipv4, dns\n\tDuration: 0.115s, DNS @0.000s took 0.002s, TCP @0.002s took 0.014s\n\tbytes in/out: 818/542, packets in/out: 2/2, rtt: 0.020s, retransmitted packets: 1, out-of-order packets: 2"); + assert_eq!(logs.raw_message, "[%{public}s %{private}@ %{public}@] cancelled\n\t[%s %{uuid_t}.16P %{private,network:in_addr}d.%d<->%{private,network:sockaddr}.*P]\n\tConnected Path: %@\n\tDuration: %u.%03us, DNS @%u.%03us took %u.%03us, %{public}s @%u.%03us took %u.%03us\n\tbytes in/out: %llu/%llu, packets in/out: %llu/%llu, rtt: %u.%03us, retransmitted packets: %llu, out-of-order packets: %u"); + } + if logs.process == "/kernel" && logs.library == "/kernel" { + kernel_entries += 1; + } + + if message_re.is_match(&logs.raw_message) { + string_count += 1; + } + } + // Opening system_logs_high_sierra.logarchive in Console.app and searching for the processes (configd, coreduetd, identityservicesd, callservicesd) above should return the exact same number of empty entries as below + assert_eq!(empty_counter, 107); + assert_eq!(empty_identityservicesd, 24); + assert_eq!(empty_configd, 64); + assert_eq!(empty_coreduetd, 1); + assert_eq!(empty_callservicesd, 18); + assert_eq!(private_entries, 88352); + assert_eq!(kernel_entries, 389); + assert_eq!(string_count, 23982); + + let mut unknown_strings = 0; + let mut invalid_offsets = 0; + let mut invalid_shared_string_offsets = 0; + let mut statedump_custom_objects = 0; + let mut statedump_protocol_buffer = 0; + for logs in &log_data_vec { + if logs.message.contains("Failed to get string message from ") + || logs.message.contains("Unknown shared string message") + { + unknown_strings += 1; + } + + if logs.message.contains("Error: Invalid offset ") { + invalid_offsets += 1; + } + + if logs.message.contains("Error: Invalid shared string offset") { + invalid_shared_string_offsets += 1; + } + + if logs.message.contains("Unsupported Statedump object") { + statedump_custom_objects += 1; + } + if logs.message.contains("Statedump Protocol Buffer") { + statedump_protocol_buffer += 1; + } + } + assert_eq!(unknown_strings, 0); + assert_eq!(invalid_offsets, 3); + assert_eq!(invalid_shared_string_offsets, 0); + assert_eq!(statedump_custom_objects, 2); + assert_eq!(statedump_protocol_buffer, 1); +} diff --git a/tests/monterey_tests.rs b/tests/monterey_tests.rs new file mode 100755 index 0000000..36acdfd --- /dev/null +++ b/tests/monterey_tests.rs @@ -0,0 +1,221 @@ +// Copyright 2022 Mandiant, Inc. 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::{fs, path::PathBuf}; + +use macos_unifiedlogs::{ + parser::{build_log, collect_shared_strings, collect_strings, collect_timesync, parse_log}, + unified_log::{LogData, UnifiedLogData}, +}; +use regex::Regex; + +fn collect_logs(path: &str) -> Vec { + let paths = fs::read_dir(path).unwrap(); + + let mut log_data_vec: Vec = Vec::new(); + for path in paths { + let data = path.unwrap(); + let full_path = data.path().display().to_string(); + let log_data = parse_log(&full_path).unwrap(); + log_data_vec.push(log_data); + } + + return log_data_vec; +} + +#[test] +fn test_parse_log_monterey() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_monterey.logarchive"); + + test_path.push("Persist/000000000000000a.tracev3"); + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + assert_eq!(log_data.catalog_data[0].firehose.len(), 17); + assert_eq!(log_data.catalog_data[0].simpledump.len(), 383); + assert_eq!(log_data.header.len(), 1); + assert_eq!( + log_data.catalog_data[0] + .catalog + .catalog_process_info_entries + .len(), + 17 + ); + assert_eq!(log_data.catalog_data[0].statedump.len(), 0); +} + +#[test] +fn test_build_log_monterey() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_monterey.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist/000000000000000a.tracev3"); + + let log_data = parse_log(&test_path.display().to_string()).unwrap(); + + let exclude_missing = false; + let (results, _) = build_log( + &log_data, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + assert_eq!(results.len(), 322859); + assert_eq!(results[0].process, "/kernel"); + assert_eq!(results[0].subsystem, ""); + assert_eq!(results[0].time, 1651345928766719209.0); + assert_eq!(results[0].activity_id, 0); + assert_eq!( + results[0].library, + "/System/Library/Extensions/Sandbox.kext/Contents/MacOS/Sandbox" + ); + assert_eq!( + results[0].message, + "2 duplicate reports for Sandbox: MTLCompilerServi(187) deny(1) file-read-metadata /private" + ); + assert_eq!(results[0].pid, 0); + assert_eq!(results[0].thread_id, 2241); + assert_eq!(results[0].category, ""); + assert_eq!(results[0].log_type, "Error"); + assert_eq!(results[0].event_type, "Log"); + assert_eq!(results[0].euid, 0); + assert_eq!(results[0].boot_uuid, "17AB576950394796B7F3CD2C157F4A2F"); + assert_eq!(results[0].timezone_name, "New_York"); + assert_eq!(results[0].library_uuid, "7EFAFB8B6CA63090957FC68A6230BC38"); + assert_eq!(results[0].process_uuid, "C342869FFFB93CCEA5A3EA711C1E87F6"); + assert_eq!(results[0].raw_message, "%s"); +} + +#[test] +fn test_parse_all_logs_monterey() { + let mut test_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + test_path.push("tests/test_data/system_logs_monterey.logarchive"); + let string_results = collect_strings(&test_path.display().to_string()).unwrap(); + + test_path.push("dsc"); + let shared_strings_results = collect_shared_strings(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("timesync"); + let timesync_data = collect_timesync(&test_path.display().to_string()).unwrap(); + test_path.pop(); + + test_path.push("Persist"); + + let mut log_data = collect_logs(&test_path.display().to_string()); + test_path.pop(); + + test_path.push("HighVolume"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("Special"); + let mut results = collect_logs(&test_path.display().to_string()); + log_data.append(&mut results); + test_path.pop(); + + test_path.push("logdata.LiveData.tracev3"); + let results = parse_log(&test_path.display().to_string()).unwrap(); + log_data.push(results); + test_path.pop(); + + let mut log_data_vec: Vec = Vec::new(); + let exclude_missing = false; + let message_re = Regex::new(r"^[\s]*%s\s*$").unwrap(); + + for logs in &log_data { + let (mut data, _) = build_log( + &logs, + &string_results, + &shared_strings_results, + ×ync_data, + exclude_missing, + ); + log_data_vec.append(&mut data); + } + assert_eq!(log_data_vec.len(), 2299798); + + let mut unknown_strings = 0; + let mut invalid_offsets = 0; + let mut invalid_shared_string_offsets = 0; + let mut statedump_custom_objects = 0; + let mut statedump_protocol_buffer = 0; + let mut string_count = 0; + + let mut mutilities_worldclock = 0; + let mut mutililties_return = 0; + let mut location_tracker = 0; + let mut pauses_tracker = 0; + let mut dns_counts = 0; + + + for logs in &log_data_vec { + if logs.message.contains("Failed to get string message from ") + || logs.message.contains("Unknown shared string message") + { + unknown_strings += 1; + } + + if logs.message.contains("Error: Invalid offset ") { + invalid_offsets += 1; + } + + if logs.message.contains("Error: Invalid shared string offset") { + invalid_shared_string_offsets += 1; + } + + if logs.message.contains("Unsupported Statedump object") { + statedump_custom_objects += 1; + } + if logs.message.contains("Statedump Protocol Buffer") { + statedump_protocol_buffer += 1; + } + + if message_re.is_match(&logs.raw_message) { + string_count += 1; + } + + if logs.message.contains("MTUtilities: WorldClockWidget:") && logs.log_type == "Default" { + mutilities_worldclock += 1; + } + if logs.message.contains("MTUtilities: Returning widget") { + mutililties_return += 1; + } + if logs.message.contains("allowsMapCorrection") { + location_tracker += 1; + } + if logs.message.contains("\"pausesLocationUpdatesAutomatically\":1,") { + pauses_tracker += 1; + } + if logs.message.contains("Question Count: 1, Answer Record Count: 0, Authority Record Count: 0, Additional Record Count: 0") { + dns_counts += 1; + } + } + assert_eq!(unknown_strings, 531); + assert_eq!(invalid_offsets, 60); + assert_eq!(invalid_shared_string_offsets, 309); + assert_eq!(statedump_custom_objects, 2); + assert_eq!(statedump_protocol_buffer, 9); + assert_eq!(string_count, 28196); // Accurate count based on log raw-dump -a | grep "format:\s*%s$" | sort | uniq -c | sort -n + assert_eq!(mutilities_worldclock, 57); + assert_eq!(mutililties_return, 71); + assert_eq!(dns_counts, 3196); + + assert_eq!(location_tracker, 298); + assert_eq!(pauses_tracker, 118); +} From 84125956d4491e764d5e5949d59f146794901898 Mon Sep 17 00:00:00 2001 From: puffyCid <16283453+puffyCid@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:27:15 -0500 Subject: [PATCH 2/3] formatting --- tests/big_sur_tests.rs | 5 ++++- tests/monterey_tests.rs | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/big_sur_tests.rs b/tests/big_sur_tests.rs index c2aa83b..1b35fe9 100755 --- a/tests/big_sur_tests.rs +++ b/tests/big_sur_tests.rs @@ -576,7 +576,10 @@ fn test_parse_all_logs_private_with_public_mix_big_sur() { user_not_found += 1; } - if logs.message.contains("refreshing: details, reason: expired, user: mobile ") { + if logs + .message + .contains("refreshing: details, reason: expired, user: mobile ") + { mobile_not_found += 1; } diff --git a/tests/monterey_tests.rs b/tests/monterey_tests.rs index 36acdfd..9153067 100755 --- a/tests/monterey_tests.rs +++ b/tests/monterey_tests.rs @@ -163,7 +163,6 @@ fn test_parse_all_logs_monterey() { let mut pauses_tracker = 0; let mut dns_counts = 0; - for logs in &log_data_vec { if logs.message.contains("Failed to get string message from ") || logs.message.contains("Unknown shared string message") @@ -199,7 +198,10 @@ fn test_parse_all_logs_monterey() { if logs.message.contains("allowsMapCorrection") { location_tracker += 1; } - if logs.message.contains("\"pausesLocationUpdatesAutomatically\":1,") { + if logs + .message + .contains("\"pausesLocationUpdatesAutomatically\":1,") + { pauses_tracker += 1; } if logs.message.contains("Question Count: 1, Answer Record Count: 0, Authority Record Count: 0, Additional Record Count: 0") { From e70b5ade5c59748f349f4ae9c35849d7b2406f56 Mon Sep 17 00:00:00 2001 From: puffyCid <16283453+puffyCid@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:37:36 -0500 Subject: [PATCH 3/3] update --- BUILDING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 2fd4c0d..7bd9807 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -11,17 +11,17 @@ # Running test suite 1. Follow steps above -2. Download `tests.zip` from Github releases -3. Copy/move `tests.zip` to clone repo -4. Decompress `tests.zip` +2. Download `test_data.zip` from Github releases +3. Copy/move `test_data.zip` to clone repo `tests` directory +4. Decompress `test_data.zip` 5. Execute `cargo test --release` to run tests * You can also just use `cargo test` to run tests but it will be slower # Running benchmarks -1. Download `tests.zip` from Github releases -2. Copy/move `tests.zip` to clone repo -3. Decompress `tests.zip` +1. Download `test_data.zip` from Github releases +2. Copy/move `test_data.zip` to clone repo `tests` directory +3. Decompress `test_data.zip` 4. Run `cargo bench` or 4. Install criterion, `cargo install cargo-criterion`