From a77c31bf0238c08fc221609e9134c1c519d584f7 Mon Sep 17 00:00:00 2001 From: Sean Klein Date: Tue, 3 Sep 2024 14:57:17 -0700 Subject: [PATCH] [tests] Use a constant-length timestamp redaction for test determinism (#6511) Changes our "timestamp redaction" logic to ignore the original length of the input timestamp. Timestamps are not always constant-width -- depending on the amount of trailing zeros, they can have variable stringified lengths. Unfortunately, this variability is at-odds with our goal of deterministic test output. In this PR, we favor the deterministic output, to avoid test flaking: Variable space output logic is removed in favor of a stable redaction marker. Additionally, tests with different timestamp lengths are added to act as a regression against this particular flake. Fixes https://github.com/oxidecomputer/omicron/issues/6509 --- Cargo.lock | 1 + dev-tools/omdb/tests/successes.out | 160 +++++++++--------- .../tests/output/cmd-stdout | 2 +- test-utils/Cargo.toml | 1 + test-utils/src/dev/test_cmds.rs | 65 ++++--- 5 files changed, 125 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1eea7f9154..0c3011f54b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6556,6 +6556,7 @@ dependencies = [ "atomicwrites", "camino", "camino-tempfile", + "chrono", "dropshot 0.10.2-dev", "expectorate", "filetime", diff --git a/dev-tools/omdb/tests/successes.out b/dev-tools/omdb/tests/successes.out index fd5f393ffc..ab68409e32 100644 --- a/dev-tools/omdb/tests/successes.out +++ b/dev-tools/omdb/tests/successes.out @@ -397,14 +397,14 @@ task: "dns_config_internal" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last generation found: 1 task: "dns_servers_internal" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms servers found: 1 DNS_SERVER_ADDR @@ -414,7 +414,7 @@ task: "dns_propagation_internal" configured period: every 1m currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms attempt to propagate generation: 1 DNS_SERVER_ADDR LAST_RESULT @@ -425,14 +425,14 @@ task: "dns_config_external" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last generation found: 2 task: "dns_servers_external" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms servers found: 1 DNS_SERVER_ADDR @@ -442,7 +442,7 @@ task: "dns_propagation_external" configured period: every 1m currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms attempt to propagate generation: 2 DNS_SERVER_ADDR LAST_RESULT @@ -453,28 +453,28 @@ task: "nat_v4_garbage_collector" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to resolve addresses for Dendrite services: no record found for Query { name: Name("_dendrite._tcp.control-plane.oxide.internal."), query_type: SRV, query_class: IN } task: "blueprint_loader" configured period: every 1m s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to read target blueprint: Internal Error: no target blueprint set task: "blueprint_executor" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: no blueprint task: "abandoned_vmm_reaper" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total abandoned VMMs found: 0 VMM records deleted: 0 VMM records already deleted by another Nexus: 0 @@ -484,28 +484,28 @@ task: "bfd_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to resolve addresses for Dendrite services: no record found for Query { name: Name("_dendrite._tcp.control-plane.oxide.internal."), query_type: SRV, query_class: IN } task: "crdb_node_id_collector" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: no blueprint task: "decommissioned_disk_cleaner" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "decommissioned_disk_cleaner" (don't know how to interpret details: Object {"deleted": Number(0), "error": Null, "error_count": Number(0), "found": Number(0), "not_ready_to_be_deleted": Number(0)}) task: "external_endpoints" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms external API endpoints: 2 ('*' below marks default) SILO_ID DNS_NAME @@ -522,7 +522,7 @@ task: "instance_updater" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total instances in need of updates: 0 instances with Destroyed active VMMs: 0 instances with Failed active VMMs: 0 @@ -534,7 +534,7 @@ task: "instance_watcher" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total instances checked: 0 checks completed: 0 successful checks: 0 @@ -547,7 +547,7 @@ task: "inventory_collection" configured period: every 10m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last collection id: ..................... last collection started: last collection done: @@ -556,7 +556,7 @@ task: "lookup_region_port" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total filled in ports: 0 errors: 0 @@ -564,14 +564,14 @@ task: "metrics_producer_gc" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms -warning: unknown background task: "metrics_producer_gc" (don't know how to interpret details: Object {"expiration": String(""), "pruned": Array []}) + started at (s ago) and ran for ms +warning: unknown background task: "metrics_producer_gc" (don't know how to interpret details: Object {"expiration": String(""), "pruned": Array []}) task: "phantom_disks" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms number of phantom disks deleted: 0 number of phantom disk delete errors: 0 @@ -579,14 +579,14 @@ task: "physical_disk_adoption" configured period: every s currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: task disabled task: "region_replacement" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms number of region replacements started ok: 0 number of region replacement start errors: 0 @@ -594,7 +594,7 @@ task: "region_replacement_driver" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms number of region replacement drive sagas started ok: 0 number of region replacement finish sagas started ok: 0 number of errors: 0 @@ -603,7 +603,7 @@ task: "region_snapshot_replacement_finish" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total records transitioned to done: 0 errors: 0 @@ -611,7 +611,7 @@ task: "region_snapshot_replacement_garbage_collection" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total garbage collections requested: 0 errors: 0 @@ -619,7 +619,7 @@ task: "region_snapshot_replacement_start" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total requests created ok: 0 total start saga invoked ok: 0 errors: 0 @@ -628,7 +628,7 @@ task: "region_snapshot_replacement_step" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total step records created ok: 0 total step garbage collect saga invoked ok: 0 total step saga invoked ok: 0 @@ -638,7 +638,7 @@ task: "saga_recovery" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms since Nexus started: sagas recovered: 0 sagas recovery errors: 0 @@ -659,34 +659,34 @@ task: "service_firewall_rule_propagation" configured period: every 5m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms task: "service_zone_nat_tracker" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: inventory collection is None task: "switch_port_config_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "switch_port_config_manager" (don't know how to interpret details: Object {}) task: "v2p_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "v2p_manager" (don't know how to interpret details: Object {}) task: "vpc_route_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "vpc_route_manager" (don't know how to interpret details: Object {}) --------------------------------------------- @@ -701,7 +701,7 @@ task: "saga_recovery" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms since Nexus started: sagas recovered: 0 sagas recovery errors: 0 @@ -730,14 +730,14 @@ task: "blueprint_loader" configured period: every 1m s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to read target blueprint: Internal Error: no target blueprint set task: "blueprint_executor" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: no blueprint --------------------------------------------- @@ -752,14 +752,14 @@ task: "dns_config_internal" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last generation found: 1 task: "dns_servers_internal" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms servers found: 1 DNS_SERVER_ADDR @@ -769,7 +769,7 @@ task: "dns_propagation_internal" configured period: every 1m currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms attempt to propagate generation: 1 DNS_SERVER_ADDR LAST_RESULT @@ -788,14 +788,14 @@ task: "dns_config_external" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last generation found: 2 task: "dns_servers_external" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms servers found: 1 DNS_SERVER_ADDR @@ -805,7 +805,7 @@ task: "dns_propagation_external" configured period: every 1m currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms attempt to propagate generation: 2 DNS_SERVER_ADDR LAST_RESULT @@ -824,14 +824,14 @@ task: "dns_config_internal" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last generation found: 1 task: "dns_servers_internal" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms servers found: 1 DNS_SERVER_ADDR @@ -841,7 +841,7 @@ task: "dns_propagation_internal" configured period: every 1m currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms attempt to propagate generation: 1 DNS_SERVER_ADDR LAST_RESULT @@ -852,14 +852,14 @@ task: "dns_config_external" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last generation found: 2 task: "dns_servers_external" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms servers found: 1 DNS_SERVER_ADDR @@ -869,7 +869,7 @@ task: "dns_propagation_external" configured period: every 1m currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms attempt to propagate generation: 2 DNS_SERVER_ADDR LAST_RESULT @@ -880,28 +880,28 @@ task: "nat_v4_garbage_collector" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to resolve addresses for Dendrite services: no record found for Query { name: Name("_dendrite._tcp.control-plane.oxide.internal."), query_type: SRV, query_class: IN } task: "blueprint_loader" configured period: every 1m s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to read target blueprint: Internal Error: no target blueprint set task: "blueprint_executor" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: no blueprint task: "abandoned_vmm_reaper" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total abandoned VMMs found: 0 VMM records deleted: 0 VMM records already deleted by another Nexus: 0 @@ -911,28 +911,28 @@ task: "bfd_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: failed to resolve addresses for Dendrite services: no record found for Query { name: Name("_dendrite._tcp.control-plane.oxide.internal."), query_type: SRV, query_class: IN } task: "crdb_node_id_collector" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: no blueprint task: "decommissioned_disk_cleaner" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "decommissioned_disk_cleaner" (don't know how to interpret details: Object {"deleted": Number(0), "error": Null, "error_count": Number(0), "found": Number(0), "not_ready_to_be_deleted": Number(0)}) task: "external_endpoints" configured period: every 1m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms external API endpoints: 2 ('*' below marks default) SILO_ID DNS_NAME @@ -949,7 +949,7 @@ task: "instance_updater" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total instances in need of updates: 0 instances with Destroyed active VMMs: 0 instances with Failed active VMMs: 0 @@ -961,7 +961,7 @@ task: "instance_watcher" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total instances checked: 0 checks completed: 0 successful checks: 0 @@ -974,7 +974,7 @@ task: "inventory_collection" configured period: every 10m currently executing: no last completed activation: , triggered by an explicit signal - started at (s ago) and ran for ms + started at (s ago) and ran for ms last collection id: ..................... last collection started: last collection done: @@ -983,7 +983,7 @@ task: "lookup_region_port" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total filled in ports: 0 errors: 0 @@ -991,14 +991,14 @@ task: "metrics_producer_gc" configured period: every 1m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms -warning: unknown background task: "metrics_producer_gc" (don't know how to interpret details: Object {"expiration": String(""), "pruned": Array []}) + started at (s ago) and ran for ms +warning: unknown background task: "metrics_producer_gc" (don't know how to interpret details: Object {"expiration": String(""), "pruned": Array []}) task: "phantom_disks" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms number of phantom disks deleted: 0 number of phantom disk delete errors: 0 @@ -1006,14 +1006,14 @@ task: "physical_disk_adoption" configured period: every s currently executing: no last completed activation: , triggered by a dependent task completing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: task disabled task: "region_replacement" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms number of region replacements started ok: 0 number of region replacement start errors: 0 @@ -1021,7 +1021,7 @@ task: "region_replacement_driver" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms number of region replacement drive sagas started ok: 0 number of region replacement finish sagas started ok: 0 number of errors: 0 @@ -1030,7 +1030,7 @@ task: "region_snapshot_replacement_finish" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total records transitioned to done: 0 errors: 0 @@ -1038,7 +1038,7 @@ task: "region_snapshot_replacement_garbage_collection" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total garbage collections requested: 0 errors: 0 @@ -1046,7 +1046,7 @@ task: "region_snapshot_replacement_start" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total requests created ok: 0 total start saga invoked ok: 0 errors: 0 @@ -1055,7 +1055,7 @@ task: "region_snapshot_replacement_step" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms total step records created ok: 0 total step garbage collect saga invoked ok: 0 total step saga invoked ok: 0 @@ -1065,7 +1065,7 @@ task: "saga_recovery" configured period: every 10m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms since Nexus started: sagas recovered: 0 sagas recovery errors: 0 @@ -1086,34 +1086,34 @@ task: "service_firewall_rule_propagation" configured period: every 5m currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms task: "service_zone_nat_tracker" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms last completion reported error: inventory collection is None task: "switch_port_config_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "switch_port_config_manager" (don't know how to interpret details: Object {}) task: "v2p_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "v2p_manager" (don't know how to interpret details: Object {}) task: "vpc_route_manager" configured period: every s currently executing: no last completed activation: , triggered by a periodic timer firing - started at (s ago) and ran for ms + started at (s ago) and ran for ms warning: unknown background task: "vpc_route_manager" (don't know how to interpret details: Object {}) --------------------------------------------- @@ -1169,7 +1169,7 @@ termination: Exited(0) --------------------------------------------- stdout: T ENA ID PARENT TIME_CREATED -* no ............. +* no ............. --------------------------------------------- stderr: note: using Nexus URL http://127.0.0.1:REDACTED_PORT/ @@ -1202,7 +1202,7 @@ WARNING: Zones exist without physical disks! METADATA: created by::::::::::: nexus-test-utils - created at::::::::::: + created at::::::::::: comment:::::::::::::: initial test blueprint internal DNS version: 1 external DNS version: 2 @@ -1240,7 +1240,7 @@ WARNING: Zones exist without physical disks! METADATA: created by::::::::::: nexus-test-utils - created at::::::::::: + created at::::::::::: comment:::::::::::::: initial test blueprint internal DNS version: 1 external DNS version: 2 diff --git a/dev-tools/reconfigurator-cli/tests/output/cmd-stdout b/dev-tools/reconfigurator-cli/tests/output/cmd-stdout index a2d6d3d17b..877ae4c3a2 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmd-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmd-stdout @@ -64,5 +64,5 @@ generated inventory collection ..................... from configu > inventory-list ID NERRORS TIME_DONE -..................... 0 +..................... 0 diff --git a/test-utils/Cargo.toml b/test-utils/Cargo.toml index f63de32e2e..242341a4e7 100644 --- a/test-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -39,6 +39,7 @@ omicron-workspace-hack.workspace = true uuid.workspace = true [dev-dependencies] +chrono.workspace = true expectorate.workspace = true gethostname.workspace = true diff --git a/test-utils/src/dev/test_cmds.rs b/test-utils/src/dev/test_cmds.rs index 5d6b9a152e..792ade0c53 100644 --- a/test-utils/src/dev/test_cmds.rs +++ b/test-utils/src/dev/test_cmds.rs @@ -155,33 +155,20 @@ pub fn redact_variable(input: &str) -> String { .to_string(); // Replace timestamps. - let s = regex::Regex::new(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z") + // + // Format: RFC 3339 (ISO 8601) + // Examples: + // 1970-01-01T00:00:00Z + // 1970-01-01T00:00:00.00001Z + // + // Note that depending on the amount of trailing zeros, + // this value can have different widths. However, "" + // has a deterministic width, so that's used instead. + let s = regex::Regex::new(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z") .unwrap() .replace_all(&s, "") .to_string(); - let s = { - let mut new_s = String::with_capacity(s.len()); - let mut last_match = 0; - for m in regex::Regex::new(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z") - .unwrap() - .find_iter(&s) - { - new_s.push_str(&s[last_match..m.start()]); - new_s.push_str("", so this subtraction can't - // underflow. Insert spaces to match widths. - for _ in 0..(m.len() - "".len()) { - new_s.push(' '); - } - new_s.push_str("TIMESTAMP>"); - last_match = m.end(); - } - new_s.push_str(&s[last_match..]); - new_s - }; - // Replace formatted durations. These are pretty specific to the background // task output. let s = regex::Regex::new(r"\d+s ago") @@ -309,6 +296,7 @@ fn fill_redaction_text(name: &str, text_to_redact_len: usize) -> String { #[cfg(test)] mod tests { use super::*; + use chrono::{DateTime, Utc}; #[test] fn test_redact_extra() { @@ -329,4 +317,35 @@ mod tests { path3: " ); } + + #[test] + fn test_redact_timestamps() { + let times = [ + DateTime::::from_timestamp_nanos(0), + DateTime::::from_timestamp_nanos(1), + DateTime::::from_timestamp_nanos(10), + DateTime::::from_timestamp_nanos(100000), + DateTime::::from_timestamp_nanos(123456789), + // This doesn't impact the test at all, but as a fun fact, this + // happened on March 18th, 2005. + DateTime::::from_timestamp_nanos(1111111111100000000), + DateTime::::from_timestamp_nanos(1111111111111100000), + DateTime::::from_timestamp_nanos(1111111111111111110), + DateTime::::from_timestamp_nanos(1111111111111111111), + // ... and this one happens on June 6th, 2040. + DateTime::::from_timestamp_nanos(2222222222000000000), + DateTime::::from_timestamp_nanos(2222222222222200000), + DateTime::::from_timestamp_nanos(2222222222222222220), + DateTime::::from_timestamp_nanos(2222222222222222222), + ]; + for time in times { + let input = format!("{:?}", time); + assert_eq!( + redact_variable(&input), + "", + "Failed to redact {:?}", + time + ); + } + } }