Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,30 @@ mod tests {

const ENDPOINT: &str = "https://api.github.com/repos/owner/repository/releases";

fn assert_accepted_delay(header: &str, delay_seconds: i64) {
let before = tracedecay_contracts::now_micros().0;
let accepted = retry_after_at(&headers_with("retry-after", header))
.unwrap_or_else(|| panic!("retry-after {header} must land {delay_seconds}s after now"));
let after = tracedecay_contracts::now_micros().0;
let delay_micros = delay_seconds * 1_000_000;
assert!(
(before + delay_micros..=after + delay_micros).contains(&accepted.0),
"retry-after {header} stamped {}, outside {before}+{delay_micros}..={after}+{delay_micros}",
accepted.0
);
}

#[test]
fn retry_after_rejects_negative_and_beyond_24h_delays() {
assert!(retry_after_at(&headers_with("retry-after", "-1")).is_none());
assert!(retry_after_at(&headers_with("retry-after", "-9999999999")).is_none());
assert!(retry_after_at(&headers_with("retry-after", "86401")).is_none());
assert!(retry_after_at(&headers_with("retry-after", "9999999999")).is_none());
assert!(retry_after_at(&headers_with("retry-after", "not-a-number")).is_none());
assert!(retry_after_at(&headers_with("retry-after", "0")).is_some());
assert!(retry_after_at(&headers_with("retry-after", "60")).is_some());
assert!(retry_after_at(&headers_with("retry-after", "86400")).is_some());
assert!(retry_after_at(&ureq::http::HeaderMap::new()).is_none());
assert_accepted_delay("0", 0);
assert_accepted_delay("60", 60);
assert_accepted_delay("86400", 86_400);
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,8 @@ impl HeldActiveDecodeV1 {
}
}

/// Last validated publication pointer, reused when the on-disk file is unchanged.
/// Last validated publication pointer. Reuse requires the file bytes' digest;
/// mtime and size alone miss a same-quantum rewrite of equal length.
struct PublicationPointerMemoV1 {
mtime: Option<SystemTime>,
size: u64,
Expand Down Expand Up @@ -1086,19 +1087,6 @@ impl DaemonCodeIndexPublicationStoreV1 {
}
let mtime = metadata.modified().ok();
let size = metadata.len();
{
let memo = self
.pointer_memo
.lock()
.unwrap_or_else(PoisonError::into_inner);
if let Some(memo) = memo.as_ref()
&& memo.size == size
&& memo.mtime.is_some()
&& memo.mtime == mtime
{
return Ok(Some(memo.pointer.clone()));
}
}
let bytes = std::fs::read(&self.active_path).map_err(Self::unavailable)?;
let digest = Self::state_digest(&bytes);
{
Expand Down
4 changes: 1 addition & 3 deletions crates/tracedecay-code-index/src/clones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ mod fingerprint_tests {
};

use super::{
CLONE_FINGERPRINT_K_V1, CLONE_FINGERPRINT_WINDOW_V1, CloneAlignmentStopReasonV1,
CLONE_FINGERPRINT_K_V1, CloneAlignmentStopReasonV1,
CloneBodyPayloadV1, CloneNormalizationClassV1, CloneTokenAnchorV1, align_clone_tokens,
select_rightmost_minima, verify_clone_token_anchor, verify_exact_clone_payload,
winnow_clone_tokens,
Expand Down Expand Up @@ -1210,8 +1210,6 @@ mod fingerprint_tests {
.len(),
1
);
assert_eq!(CLONE_FINGERPRINT_K_V1, 7);
assert_eq!(CLONE_FINGERPRINT_WINDOW_V1, 8);
}

#[test]
Expand Down
14 changes: 6 additions & 8 deletions crates/tracedecay-code-index/src/production/sealed_codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1287,18 +1287,16 @@ mod tests {

#[test]
fn format_gate_accepts_only_the_monolithic_and_partitioned_revisions() {
assert_eq!(SEALED_GENERATION_FORMAT_REVISION_V1, 12);
assert_eq!(MINIMUM_SEALED_GENERATION_FORMAT_REVISION, 9);
assert!(sealed_generation_format_revision_is_compatible(9));
assert!(sealed_generation_format_revision_is_compatible(12));
assert!(!sealed_generation_format_revision_is_compatible(8));
assert_eq!(sealed_generation_format_revision_is_compatible(9), true);
assert_eq!(sealed_generation_format_revision_is_compatible(12), true);
assert_eq!(sealed_generation_format_revision_is_compatible(8), false);
// Revision 10 stored generation-bound symbol occurrence lists.
// Revision 11 sealed generation-independent symbol identities but a
// full-corpus `full_replay_digest`. Revision 12 seals that digest as
// a parent-delta, so 11 is rebuilt rather than decoded as corruption.
assert!(!sealed_generation_format_revision_is_compatible(10));
assert!(!sealed_generation_format_revision_is_compatible(11));
assert!(!sealed_generation_format_revision_is_compatible(13));
assert_eq!(sealed_generation_format_revision_is_compatible(10), false);
assert_eq!(sealed_generation_format_revision_is_compatible(11), false);
assert_eq!(sealed_generation_format_revision_is_compatible(13), false);
}

struct LargestAllocationRecorderV1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,6 @@ fn sealed_state_digest_changes_when_ignored_source_roster_changes() {

#[test]
fn sealed_format_refuses_superseded_revisions_beside_the_partitioned_revision() {
assert_eq!(SEALED_GENERATION_FORMAT_REVISION_V1, 12);
let generation = publish(request_with_ignored_sources(vec![admission(
PRIMARY_IGNORED_PATH,
)]));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tracedecay_code_index::{
production::{
CodeIndexBuildRequestV1, CodeIndexCapturedFileV1, CodeIndexProductionErrorV1,
CodeIndexProductionOwnerV1, CodeIndexPublishedGenerationV1,
SEALED_GENERATION_FORMAT_REVISION_V1, sealed_generation_payload_digest,
sealed_generation_payload_digest,
},
};
use tracedecay_domain::{
Expand Down Expand Up @@ -960,7 +960,6 @@ fn raw_use_and_imported_bindings_never_become_canonical_symbols() {

#[test]
fn sealed_revision_nine_import_generation_round_trips_to_identical_bytes() {
assert_eq!(SEALED_GENERATION_FORMAT_REVISION_V1, 12);
let first = published_import_generation();
let first_sealed = first.encode_sealed().expect("first generation seals");
let second_sealed = published_import_generation()
Expand Down
21 changes: 18 additions & 3 deletions crates/tracedecay-contracts/src/configuration/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,24 @@ fn empty_configuration_requests_reject_transport_arguments() {

#[test]
fn configuration_schema_refs_reject_unknown_operations() {
assert!(configuration_surface_request_schema("configuration_get").is_ok());
assert!(configuration_surface_result_schema("configuration_get").is_ok());
assert!(configuration_surface_request_schema("configuration_unknown").is_err());
let request =
configuration_surface_request_schema("configuration_get").expect("get request schema");
assert_eq!(
request.schema_id().as_str(),
"schema.application.configuration.configuration_get.request"
);
let result =
configuration_surface_result_schema("configuration_get").expect("get result schema");
assert_eq!(
result.schema_id().as_str(),
"schema.application.configuration.configuration_get.result"
);
assert_eq!(
configuration_surface_request_schema("configuration_unknown").unwrap_err(),
ApplicationContractError::Inconsistent {
field: "configuration surface operation",
}
);
}

#[test]
Expand Down
22 changes: 19 additions & 3 deletions crates/tracedecay-contracts/src/feedback/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,8 @@ mod invocation_tests {
CommitId, ManifestDigest, ProjectId, RepositoryId, RetrievalAnchorId, WorktreeId,
};

use crate::error::ApplicationContractError;

use super::{
CanonicalAffectedTestsProjectionV1, CanonicalFeedbackImpactProjectionV1,
FeedbackDiagnosticsReadResultV1, FeedbackExpandResultV1, FeedbackFindingReadV1,
Expand All @@ -702,9 +704,23 @@ mod invocation_tests {

#[test]
fn invocation_handle_rejects_unbounded_or_noncanonical_feedback_reads() {
assert!(FeedbackHandleRequestV1::new("feedback.handle.v1").is_ok());
assert!(FeedbackHandleRequestV1::new(" feedback.handle.v1").is_err());
assert!(FeedbackHandleRequestV1::new("x".repeat(257)).is_err());
assert_eq!(
FeedbackHandleRequestV1::new("feedback.handle.v1")
.expect("canonical handle")
.request_handle,
"feedback.handle.v1"
);
let rejected = ApplicationContractError::InvalidIdentifier {
field: "feedback request handle",
};
assert_eq!(
FeedbackHandleRequestV1::new(" feedback.handle.v1").unwrap_err(),
rejected
);
assert_eq!(
FeedbackHandleRequestV1::new("x".repeat(257)).unwrap_err(),
rejected
);
}

#[test]
Expand Down
51 changes: 41 additions & 10 deletions crates/tracedecay-contracts/src/remote/query_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use super::query::{
validate_returned_authority, validate_returned_observation_identity,
validate_returned_provenance,
};
use crate::{RequestId, ResolvedScope};
use crate::{ApplicationContractError, RequestId, ResolvedScope};
use tracedecay_domain::{
AuthorityEpoch, BrainId, BrainNodeId, CanonicalObservationIdV1, CurrentRemoteAuthorityStateV1,
CurrentRemoteAuthorityV1, EnrollmentCredentialRecordV1, EntityId, EvidenceAvailabilityV1,
Expand Down Expand Up @@ -133,36 +133,67 @@ fn exact_observation_absence_round_trips_as_explicit_state() {

#[test]
fn remote_query_request_enforces_shard_inventory_bounds_and_identity() {
assert!(request(Vec::new()).validate().is_err());
assert!(request(vec![shard(1)]).validate().is_ok());
assert!(request(vec![shard(1), shard(2)]).validate().is_err());
assert!(request(vec![shard(1), shard(1)]).validate().is_err());
let range = ApplicationContractError::InvalidRange {
field: "remote query expected shard inventory",
};
assert_eq!(request(Vec::new()).validate(), Err(range.clone()));
let accepted = request(vec![shard(1)]);
assert_eq!(accepted.validate(), Ok(()));
assert_eq!(accepted.expected_shards[0].shard_id, "shard.remote-query.1");
assert_eq!(
request(vec![shard(1), shard(2)]).validate(),
Err(range.clone())
);
assert_eq!(
request(vec![shard(1), shard(1)]).validate(),
Err(range.clone())
);

let mut mixed = shard(2);
mixed.brain_id = "brain.other".to_owned();
assert!(request(vec![shard(1), mixed]).validate().is_err());
assert_eq!(request(vec![shard(1), mixed]).validate(), Err(range));
}

#[test]
fn remote_query_request_binds_inventory_to_expected_fence() {
let mut mismatched_brain = request(vec![shard(1)]);
mismatched_brain.expected_shards[0].brain_id = "brain.other".into();
assert!(mismatched_brain.validate().is_err());
assert_eq!(
mismatched_brain.validate(),
Err(ApplicationContractError::Inconsistent {
field: "remote query authority inventory binding",
})
);

let mut mismatched_shard = request(vec![shard(1)]);
mismatched_shard.expected_shards[0].shard_id = "shard.other".into();
assert!(mismatched_shard.validate().is_err());
assert_eq!(
mismatched_shard.validate(),
Err(ApplicationContractError::Inconsistent {
field: "remote query authority inventory binding",
})
);

let mut mismatched_generation = request(vec![shard(1)]);
mismatched_generation.expected_shards[0].generation_id = "generation.other".into();
assert!(mismatched_generation.validate().is_err());
assert_eq!(
mismatched_generation.validate(),
Err(ApplicationContractError::Inconsistent {
field: "remote query authority inventory binding",
})
);
}

#[test]
fn remote_query_request_rejects_invalid_shard_identifiers() {
let mut invalid = shard(1);
invalid.generation_id = " generation.remote-query ".to_owned();
assert!(request(vec![invalid]).validate().is_err());
assert_eq!(
request(vec![invalid]).validate(),
Err(ApplicationContractError::InvalidIdentifier {
field: "remote query generation identity",
})
);
}

#[test]
Expand Down
23 changes: 20 additions & 3 deletions crates/tracedecay-contracts/src/result/problem/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use tracedecay_domain::errors::TraceDecayError;

use crate::ApplicationContractError;

use super::{
ApplicationExecutionFailureClassV1, ApplicationProblem, ApplicationProblemKind,
ApplicationUnavailableClassV1, CancellationStage, LegalAction, ProblemTerminality,
Expand Down Expand Up @@ -80,12 +82,27 @@ fn cancellation_after_effect_or_during_reconciliation_is_not_a_no_effect_termina
CancellationStage::Reconciling,
CancellationStage::AfterCommit,
] {
assert!(ApplicationProblem::cancelled(stage).is_err());
assert!(ApplicationProblem::timed_out(stage).is_err());
assert_eq!(
ApplicationProblem::cancelled(stage),
Err(ApplicationContractError::Inconsistent {
field: "application problem cancellation stage",
})
);
assert_eq!(
ApplicationProblem::timed_out(stage),
Err(ApplicationContractError::Inconsistent {
field: "application problem cancellation stage",
})
);
let wire = serde_json::json!({
"kind": "cancelled", "stage": stage, "retry": "never", "legal_actions": []
});
assert!(serde_json::from_value::<ApplicationProblem>(wire).is_err());
assert_eq!(
serde_json::from_value::<ApplicationProblem>(wire)
.unwrap_err()
.to_string(),
"application problem cancellation stage is inconsistent with the application contract"
);
}
}

Expand Down
22 changes: 15 additions & 7 deletions crates/tracedecay-contracts/src/storage/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,12 @@ mod tests {

#[test]
fn store_key_rejects_empty_untrimmed_and_control() {
assert!(StoreKeyV1::new("").is_err());
assert!(StoreKeyV1::new(" leading").is_err());
assert!(StoreKeyV1::new("ctrl\u{0}char").is_err());
let rejected = ApplicationContractError::InvalidIdentifier {
field: "storage store key",
};
assert_eq!(StoreKeyV1::new("").unwrap_err(), rejected);
assert_eq!(StoreKeyV1::new(" leading").unwrap_err(), rejected);
assert_eq!(StoreKeyV1::new("ctrl\u{0}char").unwrap_err(), rejected);
assert_eq!(
StoreKeyV1::new("sessions.db").expect("valid").as_str(),
"sessions.db"
Expand All @@ -140,9 +143,14 @@ mod tests {

#[test]
fn free_page_ratio_new_rejects_out_of_range() {
assert!(FreePageRatioV1::new(-0.1).is_err());
assert!(FreePageRatioV1::new(1.5).is_err());
assert!(FreePageRatioV1::new(f64::NAN).is_err());
assert!(FreePageRatioV1::new(0.5).is_ok());
let rejected = ApplicationContractError::InvalidRange {
field: "storage free page ratio",
};
assert_eq!(FreePageRatioV1::new(-0.1).unwrap_err(), rejected);
assert_eq!(FreePageRatioV1::new(1.5).unwrap_err(), rejected);
assert_eq!(FreePageRatioV1::new(f64::NAN).unwrap_err(), rejected);
assert_eq!(FreePageRatioV1::new(0.0).expect("zero").as_f64(), 0.0);
assert_eq!(FreePageRatioV1::new(0.5).expect("half").as_f64(), 0.5);
assert_eq!(FreePageRatioV1::new(1.0).expect("full").as_f64(), 1.0);
}
}
Loading
Loading