commit 7b24c1c8706571fedd28f6476a99afd3943c881a
parent 47ef6f21ed8a157d0cac900ea18e75f9f0377157
Author: triesap <tyson@radroots.org>
Date: Fri, 19 Jun 2026 04:29:59 -0700
runtime: align order lifecycle SDK evidence tests
- Sign app order lifecycle fixture events with deterministic test identities.
- Assert SDK migration receipts for migrated lifecycle publish paths.
- Align rejected payment evidence with the pre-payment lifecycle boundary.
- Keep reducer-invalid fixtures distinct under verified event ids.
Diffstat:
1 file changed, 445 insertions(+), 373 deletions(-)
diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs
@@ -10288,9 +10288,9 @@ fn active_order_current_parent_event_id(
fn active_order_payment_blocks_lifecycle_write(
lifecycle: &ResolvedAppOrderLifecycleEvidence,
) -> bool {
- matches!(
+ !matches!(
lifecycle.payment_state,
- RadrootsOrderPaymentState::Recorded | RadrootsOrderPaymentState::Settled
+ RadrootsOrderPaymentState::NotRecorded
)
}
@@ -10668,6 +10668,7 @@ mod tests {
use radroots_events_codec::order::{
order_payment_record_event_build, order_settlement_decision_event_build,
};
+ use radroots_events_codec::wire::WireEventParts;
use radroots_identity::{RadrootsIdentity, RadrootsIdentityId};
use radroots_local_events::{
BUYER_ORDER_REQUEST_LOCAL_WORK_RECORD_KIND, LocalEventRecord, LocalEventRecordInput,
@@ -10696,7 +10697,10 @@ mod tests {
RadrootsOrderSettlementDecision, RadrootsOrderSettlementOutcome,
};
use radroots_sdk::{
- LISTING_PUBLISH_OPERATION_KIND, ORDER_DECISION_OPERATION_KIND, ORDER_SUBMIT_OPERATION_KIND,
+ LISTING_PUBLISH_OPERATION_KIND, ORDER_CANCELLATION_OPERATION_KIND,
+ ORDER_DECISION_OPERATION_KIND, ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
+ ORDER_RECEIPT_RECORD_OPERATION_KIND, ORDER_REVISION_DECISION_OPERATION_KIND,
+ ORDER_SUBMIT_OPERATION_KIND,
};
use radroots_sql_core::{SqlExecutor, SqliteExecutor};
use radroots_trade::order::radroots_order_economics_digest;
@@ -10712,6 +10716,10 @@ mod tests {
"10c5304d6c9ae3a1a16f7860f1cc8f5e3a76225a2663b3a989a0d775919b7df5";
const SDK_TEST_BUYER_PUBLIC_KEY_HEX: &str =
"585591529da0bab31b3b1b1f986611cf5f435dca84f978c89ee8a40cca7103df";
+ const SDK_TEST_SELLER_SECRET_KEY_HEX: &str =
+ "59392e9068f66431b12f70218fb61281cb6b433d7f27c55d61f1a63fe1a96ff8";
+ const SDK_TEST_SELLER_PUBLIC_KEY_HEX: &str =
+ "e0266e3cfb0d2886f91c73f5f868f3b98273713e5fcd97c081663f5518a4b3af";
use super::{
APP_DATABASE_FILE_NAME, APP_SYNC_PUBLISH_USES_SDK_RUNTIME_MESSAGE,
@@ -10720,8 +10728,8 @@ mod tests {
DesktopAppSdkDiagnosticsState, DesktopAppSyncStatusSummary, DesktopRemoteSignerPaths,
SYNC_TRANSPORT_UNAVAILABLE_MESSAGE, TokioRuntimeBuilder, default_sync_transport,
direct_relay_event_source_runtime, farm_sync_payload, is_hex_64,
- order_decision_publish_payload_to_sdk_decision, pending_sync_upsert,
- signed_event_from_local_record,
+ order_decision_publish_payload_to_sdk_decision, order_fulfillment_status_storage_key,
+ pending_sync_upsert, signed_event_from_local_record,
};
use crate::pack_day_host_handoff::PackDayHostHandoffError;
use crate::pack_day_print::{
@@ -11029,12 +11037,75 @@ mod tests {
test_event_id_seed(record_id)
}
- fn signed_listing_event_id(label: &str) -> String {
- signed_event_id(format!("app:signed_event:listing:{label}").as_str())
+ fn test_event_signature_seed(seed: &str) -> String {
+ let base = test_event_id_seed(seed);
+ format!("{base}{base}")
+ }
+
+ fn test_event_created_at(seed: &str, base: u32) -> u32 {
+ let offset = seed
+ .bytes()
+ .fold(0u32, |acc, byte| (acc + u32::from(byte)) % 900);
+ base + offset
+ }
+
+ fn signed_test_event(
+ secret_key_hex: &str,
+ created_at: u32,
+ parts: WireEventParts,
+ ) -> SdkRadrootsNostrEvent {
+ let secret_key = RadrootsNostrSecretKey::from_hex(secret_key_hex).expect("secret key");
+ let keys = RadrootsNostrKeys::new(secret_key);
+ let event = radroots_nostr_build_event(parts.kind, parts.content, parts.tags)
+ .expect("test event builder")
+ .custom_created_at(RadrootsNostrTimestamp::from_secs(u64::from(created_at)))
+ .sign_with_keys(&keys)
+ .expect("test event should sign");
+ radroots_event_from_nostr(&event)
+ }
+
+ fn signed_test_event_for_pubkey(
+ pubkey: &str,
+ created_at: u32,
+ parts: WireEventParts,
+ ) -> Option<SdkRadrootsNostrEvent> {
+ match pubkey {
+ SDK_TEST_BUYER_PUBLIC_KEY_HEX => Some(signed_test_event(
+ SDK_TEST_BUYER_SECRET_KEY_HEX,
+ created_at,
+ parts,
+ )),
+ SDK_TEST_SELLER_PUBLIC_KEY_HEX => Some(signed_test_event(
+ SDK_TEST_SELLER_SECRET_KEY_HEX,
+ created_at,
+ parts,
+ )),
+ _ => None,
+ }
+ }
+
+ fn test_event_from_parts(
+ record_id: &str,
+ event_id: String,
+ event_pubkey: &str,
+ created_at: u32,
+ parts: WireEventParts,
+ ) -> SdkRadrootsNostrEvent {
+ signed_test_event_for_pubkey(event_pubkey, created_at, parts.clone()).unwrap_or_else(|| {
+ SdkRadrootsNostrEvent {
+ id: event_id,
+ author: event_pubkey.to_owned(),
+ created_at,
+ kind: parts.kind,
+ tags: parts.tags,
+ content: parts.content,
+ sig: test_event_signature_seed(record_id),
+ }
+ })
}
- fn signed_order_request_event_id(trade_order_id: &str) -> String {
- signed_event_id(format!("app:signed_event:order-request:{trade_order_id}").as_str())
+ fn signed_listing_event_id(label: &str) -> String {
+ signed_event_id(format!("app:signed_event:listing:{label}").as_str())
}
fn test_order_id(value: &str) -> RadrootsOrderId {
@@ -15800,7 +15871,7 @@ mod tests {
assert_eq!(payload.trade_order_id, "seller-order-decision-1");
assert_eq!(
payload.request_event_id,
- signed_order_request_event_id("seller-order-decision-1")
+ shared_order_request_event_id(&paths, "seller-order-decision-1")
);
assert_eq!(
payload.listing_event_id,
@@ -15866,7 +15937,7 @@ mod tests {
assert_eq!(payload.trade_order_id, "seller-order-decision-1");
assert_eq!(
payload.request_event_id,
- signed_order_request_event_id("seller-order-decision-1")
+ shared_order_request_event_id(&paths, "seller-order-decision-1")
);
cleanup_bootstrapped_runtime_paths(&paths);
@@ -16044,36 +16115,31 @@ mod tests {
#[test]
fn runtime_publishes_all_seller_fulfillment_states_and_projects_signed_evidence() {
- for (label, action, expected_status, expected_order_status) in [
+ for (label, action, expected_status) in [
(
"preparing",
OrderFulfillmentAction::Preparing,
RadrootsOrderFulfillmentState::Preparing,
- "scheduled",
),
(
"ready_for_pickup",
OrderFulfillmentAction::ReadyForPickup,
RadrootsOrderFulfillmentState::ReadyForPickup,
- "packed",
),
(
"out_for_delivery",
OrderFulfillmentAction::OutForDelivery,
RadrootsOrderFulfillmentState::OutForDelivery,
- "packed",
),
(
"delivered",
OrderFulfillmentAction::Delivered,
RadrootsOrderFulfillmentState::Delivered,
- "packed",
),
(
"seller_cancelled",
OrderFulfillmentAction::SellerCancelled,
RadrootsOrderFulfillmentState::SellerCancelled,
- "declined",
),
] {
let relay = ThreadedAckRelay::spawn();
@@ -16096,26 +16162,17 @@ mod tests {
.expect("seller fulfillment update should publish")
);
- assert_eq!(
- persisted_order_status(&runtime, order_id),
- expected_order_status
- );
- assert_eq!(relay.event_count(), 2);
+ assert_eq!(persisted_order_status(&runtime, order_id), "scheduled");
+ assert_eq!(relay.event_count(), 1);
let fulfillment_events =
shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert_eq!(fulfillment_events.len(), 1);
- let fulfillment_event = fulfillment_events.first().expect("fulfillment event");
- let envelope =
- radroots_sdk::protocol::order::parse_fulfillment_update(fulfillment_event)
- .expect("fulfillment should parse");
- assert_eq!(envelope.payload.status, expected_status);
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
- assert!(event_has_tag(
- fulfillment_event,
- "e_root",
- request_event_id.as_str()
- ));
- assert!(event_has_nonempty_value_tag(fulfillment_event, "e_prev"));
+ assert!(fulfillment_events.is_empty());
+ assert_order_fulfillment_sdk_migration_receipt(
+ &runtime,
+ order_id,
+ expected_status,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&paths);
}
@@ -16139,7 +16196,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -16162,18 +16219,19 @@ mod tests {
seller_pubkey.as_str(),
);
let revision_id = format!("revision-{proposal_key}");
- let revision_decision_event_id = append_signed_order_revision_decision_record_with_prev(
- &paths,
- "seller-order-decision-1",
- format!("seller-order-ready-revision-{label}-decision").as_str(),
- request_event_id,
- proposal_event_id.as_str(),
- revision_id.as_str(),
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- revision_decision,
- );
+ let _revision_decision_event_id =
+ append_signed_order_revision_decision_record_with_prev(
+ &paths,
+ "seller-order-decision-1",
+ format!("seller-order-ready-revision-{label}-decision").as_str(),
+ request_event_id,
+ proposal_event_id.as_str(),
+ revision_id.as_str(),
+ listing_addr.as_str(),
+ buyer_pubkey.as_str(),
+ seller_pubkey.as_str(),
+ revision_decision,
+ );
runtime
.refresh_shared_local_events()
.expect("seller revision fixture should import");
@@ -16188,16 +16246,16 @@ mod tests {
.expect("seller ready fulfillment should publish from revision parent")
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let fulfillment_events =
shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert_eq!(fulfillment_events.len(), 1);
- let ready_event = fulfillment_events.first().expect("ready event");
- assert!(event_has_tag(
- ready_event,
- "e_prev",
- revision_decision_event_id.as_str()
- ));
+ assert!(fulfillment_events.is_empty());
+ assert_order_fulfillment_sdk_migration_receipt(
+ &runtime,
+ order_id,
+ RadrootsOrderFulfillmentState::ReadyForPickup,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&paths);
}
@@ -16211,7 +16269,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -16222,7 +16280,7 @@ mod tests {
seller_pubkey.as_str(),
2,
);
- let ready_event_id = append_signed_order_fulfillment_record_with_status(
+ let _ready_event_id = append_signed_order_fulfillment_record_with_status(
&paths,
"seller-order-decision-1",
request_event_id,
@@ -16244,25 +16302,16 @@ mod tests {
.expect("seller delivered fulfillment should publish from workflow evidence")
);
- assert_eq!(persisted_order_status(&runtime, order_id), "packed");
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(persisted_order_status(&runtime, order_id), "scheduled");
+ assert_eq!(relay.event_count(), 0);
let fulfillment_events = shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- assert_eq!(fulfillment_events.len(), 2);
- let delivered_event = fulfillment_events
- .iter()
- .find(|event| {
- radroots_sdk::protocol::order::parse_fulfillment_update(event)
- .map(|envelope| {
- envelope.payload.status == RadrootsOrderFulfillmentState::Delivered
- })
- .unwrap_or(false)
- })
- .expect("delivered fulfillment event should exist");
- assert!(event_has_tag(
- delivered_event,
- "e_prev",
- ready_event_id.as_str()
- ));
+ assert_eq!(fulfillment_events.len(), 1);
+ assert_order_fulfillment_sdk_migration_receipt(
+ &runtime,
+ order_id,
+ RadrootsOrderFulfillmentState::Delivered,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&paths);
}
@@ -16282,7 +16331,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -16315,30 +16364,20 @@ mod tests {
.expect("seller delivered fulfillment should publish")
);
- assert_eq!(persisted_order_status(&runtime, order_id), "packed");
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(persisted_order_status(&runtime, order_id), "scheduled");
+ assert_eq!(relay.event_count(), 0);
let fulfillment_events =
shared_order_events_by_kind(&paths, 3433, seller_pubkey.as_str());
- let delivered_event = fulfillment_events
- .iter()
- .find(|event| {
- radroots_sdk::protocol::order::parse_fulfillment_update(event)
- .map(|envelope| {
- envelope.payload.status == RadrootsOrderFulfillmentState::Delivered
- })
- .unwrap_or(false)
- })
- .expect("delivered fulfillment event should exist");
- assert!(event_has_tag(
- delivered_event,
- "e_prev",
- latest_fulfillment
- .map(|_| {
- signed_event_id("app:signed_event:fulfillment:seller-order-decision-1")
- })
- .unwrap_or_else(|| decision_event_id.clone())
- .as_str()
- ));
+ assert_eq!(
+ fulfillment_events.len(),
+ usize::from(latest_fulfillment.is_some())
+ );
+ assert_order_fulfillment_sdk_migration_receipt(
+ &runtime,
+ order_id,
+ RadrootsOrderFulfillmentState::Delivered,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&paths);
}
}
@@ -16355,7 +16394,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -16425,7 +16464,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
append_signed_order_decision_record(
&paths,
@@ -16479,7 +16518,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
append_signed_order_decision_record(
&paths,
@@ -16528,7 +16567,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -16591,14 +16630,14 @@ mod tests {
}
#[test]
- fn runtime_publishes_seller_order_revision_after_rejected_settlement_evidence() {
+ fn runtime_rejects_seller_order_revision_after_rejected_settlement_evidence() {
let relay = ThreadedAckRelay::spawn();
let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
seller_order_decision_runtime("seller_order_revision_rejected_payment", 6, 2);
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -16638,25 +16677,24 @@ mod tests {
.expect("seller rejected payment evidence should import");
set_persisted_order_status(&runtime, order_id, "scheduled");
- assert!(
- runtime
- .publish_order_revision_proposal(
- order_id,
- revision_test_order_items(),
- revision_test_order_economics(),
- "harvest count updated",
- )
- .expect("seller revision proposal should publish after rejected 3436")
- );
+ let error = runtime
+ .publish_order_revision_proposal(
+ order_id,
+ revision_test_order_items(),
+ revision_test_order_economics(),
+ "harvest count updated",
+ )
+ .expect_err("seller revision proposal should reject rejected 3436 payment evidence");
- assert_eq!(relay.event_count(), 1);
- let revision_events = shared_order_events_by_kind(&paths, 3424, seller_pubkey.as_str());
- assert_eq!(revision_events.len(), 1);
- assert!(event_has_tag(
- revision_events.first().expect("seller revision event"),
- "e_prev",
- decision_event_id.as_str()
+ assert!(matches!(
+ error,
+ AppSqliteError::InvalidProjection {
+ reason: "seller order revision requires no recorded or settled payment"
+ }
));
+ assert_eq!(relay.event_count(), 0);
+ let revision_events = shared_order_events_by_kind(&paths, 3424, seller_pubkey.as_str());
+ assert!(revision_events.is_empty());
cleanup_bootstrapped_runtime_paths(&paths);
}
@@ -16668,7 +16706,7 @@ mod tests {
install_direct_relay_sync_transport(&runtime, &relay);
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = signed_order_request_event_id("seller-order-decision-1");
+ let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
let request_event_id = request_event_id.as_str();
let decision_event_id = append_signed_order_decision_record(
&paths,
@@ -17307,31 +17345,17 @@ mod tests {
assert_eq!(
persisted_order_status(&fixture.runtime, fixture.order_id),
- "declined"
+ "scheduled"
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let cancellation_events =
shared_order_events_by_kind(&fixture.paths, 3432, fixture.buyer_pubkey.as_str());
- assert_eq!(cancellation_events.len(), 1);
- let cancellation_event = cancellation_events
- .first()
- .expect("linked buyer cancellation event");
- let cancellation =
- radroots_sdk::protocol::order::parse_order_cancellation(cancellation_event)
- .expect("linked buyer cancellation should parse");
- assert_eq!(cancellation.payload.order_id, fixture.trade_order_id);
- assert_eq!(cancellation.payload.buyer_pubkey, fixture.buyer_pubkey);
- assert_eq!(cancellation.payload.seller_pubkey, fixture.seller_pubkey);
- assert!(event_has_tag(
- cancellation_event,
- "e_root",
- fixture.request_event_id.as_str()
- ));
- assert!(event_has_tag(
- cancellation_event,
- "e_prev",
- fixture.decision_event_id.as_str()
- ));
+ assert!(cancellation_events.is_empty());
+ assert_order_cancellation_sdk_migration_receipt(
+ &fixture.runtime,
+ fixture.order_id,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -17400,7 +17424,7 @@ mod tests {
}
#[test]
- fn runtime_publishes_linked_buyer_cancellation_after_rejected_settlement_evidence() {
+ fn runtime_rejects_linked_buyer_cancellation_after_rejected_settlement_evidence() {
let relay = ThreadedAckRelay::spawn();
let fixture =
linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_rejected_payment", false);
@@ -17440,24 +17464,21 @@ mod tests {
.expect("linked buyer order detail should open")
);
- assert!(
- fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id)
- .expect("linked buyer cancellation should publish after rejected 3436")
- );
+ let error = fixture
+ .runtime
+ .publish_buyer_order_cancel(fixture.order_id)
+ .expect_err("linked buyer cancellation should reject rejected 3436 payment evidence");
- assert_eq!(relay.event_count(), 1);
+ assert!(matches!(
+ error,
+ AppSqliteError::InvalidProjection {
+ reason: "buyer order cancellation requires no recorded or settled payment"
+ }
+ ));
+ assert_eq!(relay.event_count(), 0);
let cancellation_events =
shared_order_events_by_kind(&fixture.paths, 3432, fixture.buyer_pubkey.as_str());
- assert_eq!(cancellation_events.len(), 1);
- assert!(event_has_tag(
- cancellation_events
- .first()
- .expect("linked buyer cancellation event"),
- "e_prev",
- fixture.decision_event_id.as_str()
- ));
+ assert!(cancellation_events.is_empty());
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -17657,18 +17678,19 @@ mod tests {
fixture.seller_pubkey.as_str(),
);
let revision_id = format!("revision-{proposal_key}");
- let revision_decision_event_id = append_signed_order_revision_decision_record_with_prev(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- format!("linked-buyer-order-cancel-revision-{label}-decision").as_str(),
- fixture.request_event_id.as_str(),
- proposal_event_id.as_str(),
- revision_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- revision_decision,
- );
+ let _revision_decision_event_id =
+ append_signed_order_revision_decision_record_with_prev(
+ &fixture.paths,
+ fixture.trade_order_id.as_str(),
+ format!("linked-buyer-order-cancel-revision-{label}-decision").as_str(),
+ fixture.request_event_id.as_str(),
+ proposal_event_id.as_str(),
+ revision_id.as_str(),
+ fixture.listing_addr.as_str(),
+ fixture.buyer_pubkey.as_str(),
+ fixture.seller_pubkey.as_str(),
+ revision_decision,
+ );
install_direct_relay_sync_transport(&fixture.runtime, &relay);
fixture
.runtime
@@ -17689,18 +17711,15 @@ mod tests {
.expect("linked buyer cancellation should publish from revision parent")
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let cancellation_events =
shared_order_events_by_kind(&fixture.paths, 3432, fixture.buyer_pubkey.as_str());
- assert_eq!(cancellation_events.len(), 1);
- let cancellation_event = cancellation_events
- .first()
- .expect("linked buyer cancellation event");
- assert!(event_has_tag(
- cancellation_event,
- "e_prev",
- revision_decision_event_id.as_str()
- ));
+ assert!(cancellation_events.is_empty());
+ assert_order_cancellation_sdk_migration_receipt(
+ &fixture.runtime,
+ fixture.order_id,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -17710,7 +17729,7 @@ mod tests {
fn runtime_publishes_linked_buyer_receipt_from_selected_account_nostr_scope() {
let relay = ThreadedAckRelay::spawn();
let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_receipt", true);
- let fulfillment_event_id = fixture
+ let _fulfillment_event_id = fixture
.fulfillment_event_id
.as_deref()
.expect("ready fixture should include fulfillment event")
@@ -17748,29 +17767,17 @@ mod tests {
assert_eq!(
persisted_order_status(&fixture.runtime, fixture.order_id),
- "completed"
+ "packed"
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let receipt_events =
shared_order_events_by_kind(&fixture.paths, 3434, fixture.buyer_pubkey.as_str());
- assert_eq!(receipt_events.len(), 1);
- let receipt_event = receipt_events.first().expect("linked buyer receipt event");
- let receipt = radroots_sdk::protocol::order::parse_buyer_receipt(receipt_event)
- .expect("linked buyer receipt should parse");
- assert_eq!(receipt.payload.order_id, fixture.trade_order_id);
- assert_eq!(receipt.payload.buyer_pubkey, fixture.buyer_pubkey);
- assert_eq!(receipt.payload.seller_pubkey, fixture.seller_pubkey);
- assert!(receipt.payload.received);
- assert!(event_has_tag(
- receipt_event,
- "e_root",
- fixture.request_event_id.as_str()
- ));
- assert!(event_has_tag(
- receipt_event,
- "e_prev",
- fulfillment_event_id.as_str()
- ));
+ assert!(receipt_events.is_empty());
+ assert_order_receipt_sdk_migration_receipt(
+ &fixture.runtime,
+ fixture.order_id,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -17779,7 +17786,7 @@ mod tests {
fn runtime_publishes_linked_buyer_receipt_after_direct_delivered_fulfillment() {
let relay = ThreadedAckRelay::spawn();
let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_receipt_delivered", false);
- let fulfillment_event_id = append_signed_order_fulfillment_record_with_status(
+ let _fulfillment_event_id = append_signed_order_fulfillment_record_with_status(
&fixture.paths,
fixture.trade_order_id.as_str(),
fixture.request_event_id.as_str(),
@@ -17810,21 +17817,17 @@ mod tests {
assert_eq!(
persisted_order_status(&fixture.runtime, fixture.order_id),
- "completed"
+ "packed"
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let receipt_events =
shared_order_events_by_kind(&fixture.paths, 3434, fixture.buyer_pubkey.as_str());
- assert_eq!(receipt_events.len(), 1);
- let receipt_event = receipt_events.first().expect("linked buyer receipt event");
- let receipt = radroots_sdk::protocol::order::parse_buyer_receipt(receipt_event)
- .expect("linked buyer delivered receipt should parse");
- assert!(receipt.payload.received);
- assert!(event_has_tag(
- receipt_event,
- "e_prev",
- fulfillment_event_id.as_str()
- ));
+ assert!(receipt_events.is_empty());
+ assert_order_receipt_sdk_migration_receipt(
+ &fixture.runtime,
+ fixture.order_id,
+ AppSdkMigrationState::Enqueued,
+ );
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -17858,19 +17861,12 @@ mod tests {
assert_eq!(
persisted_order_status(&fixture.runtime, fixture.order_id),
- "needs_review"
+ "packed"
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let receipt_events =
shared_order_events_by_kind(&fixture.paths, 3434, fixture.buyer_pubkey.as_str());
- assert_eq!(receipt_events.len(), 1);
- let receipt_event = receipt_events
- .first()
- .expect("linked buyer issue receipt event");
- let receipt = radroots_sdk::protocol::order::parse_buyer_receipt(receipt_event)
- .expect("linked buyer issue receipt should parse");
- assert!(!receipt.payload.received);
- assert_eq!(receipt.payload.issue.as_deref(), Some("items need review"));
+ assert!(receipt_events.is_empty());
let buyer_detail = fixture
.runtime
.summary()
@@ -17880,16 +17876,11 @@ mod tests {
.as_ref()
.expect("linked buyer issue receipt detail")
.clone();
- assert_eq!(buyer_detail.status, BuyerOrderStatus::NeedsReview);
- let projected_receipt = buyer_detail
- .workflow
- .receipt
- .as_ref()
- .expect("receipt projection should be present");
- assert!(!projected_receipt.received);
- assert_eq!(
- projected_receipt.issue.as_deref(),
- Some("items need review")
+ assert_eq!(buyer_detail.status, BuyerOrderStatus::Ready);
+ assert_order_receipt_sdk_migration_receipt(
+ &fixture.runtime,
+ fixture.order_id,
+ AppSdkMigrationState::Enqueued,
);
cleanup_bootstrapped_runtime_paths(&fixture.paths);
@@ -17995,16 +17986,18 @@ mod tests {
fn runtime_publishes_linked_buyer_revision_decision_from_reducer_valid_parent() {
let relay = ThreadedAckRelay::spawn();
let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_revision", false);
- let proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
+ let proposal_key = "linked-buyer-order-revision-proposal";
+ let _proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
&fixture.paths,
fixture.trade_order_id.as_str(),
- "linked-buyer-order-revision-proposal",
+ proposal_key,
fixture.request_event_id.as_str(),
fixture.decision_event_id.as_str(),
fixture.listing_addr.as_str(),
fixture.buyer_pubkey.as_str(),
fixture.seller_pubkey.as_str(),
);
+ let revision_id = format!("revision-{proposal_key}");
install_direct_relay_sync_transport(&fixture.runtime, &relay);
fixture
.runtime
@@ -18024,30 +18017,16 @@ mod tests {
.expect("linked buyer revision decision should publish")
);
- assert_eq!(relay.event_count(), 1);
+ assert_eq!(relay.event_count(), 0);
let revision_decision_events =
shared_order_events_by_kind(&fixture.paths, 3425, fixture.buyer_pubkey.as_str());
- assert_eq!(revision_decision_events.len(), 1);
- let revision_decision_event = revision_decision_events
- .first()
- .expect("linked buyer revision decision event");
- let revision_decision =
- radroots_sdk::protocol::order::parse_order_revision_decision(revision_decision_event)
- .expect("linked buyer revision decision should parse");
- assert_eq!(
- revision_decision.payload.decision,
- RadrootsOrderRevisionOutcome::Accepted
+ assert!(revision_decision_events.is_empty());
+ assert_order_revision_decision_sdk_migration_receipt(
+ &fixture.runtime,
+ fixture.order_id,
+ revision_id.as_str(),
+ AppSdkMigrationState::Enqueued,
);
- assert!(event_has_tag(
- revision_decision_event,
- "e_root",
- fixture.request_event_id.as_str()
- ));
- assert!(event_has_tag(
- revision_decision_event,
- "e_prev",
- proposal_event_id.as_str()
- ));
cleanup_bootstrapped_runtime_paths(&fixture.paths);
}
@@ -21413,7 +21392,7 @@ mod tests {
linked_buyer_lifecycle_runtime_with_seller_pubkey(
label,
include_ready_fulfillment,
- "2222222222222222222222222222222222222222222222222222222222222222",
+ SDK_TEST_SELLER_PUBLIC_KEY_HEX,
)
}
@@ -21425,8 +21404,10 @@ mod tests {
let (runtime, paths) = bootstrapped_runtime(label);
assert!(
runtime
- .generate_local_account(Some("Buyer".to_owned()))
- .expect("buyer account should generate")
+ .import_local_account(DesktopLocalIdentityImportRequest::raw_secret_key(
+ SDK_TEST_BUYER_SECRET_KEY_HEX,
+ ))
+ .expect("buyer account should import")
);
assert!(
runtime
@@ -21467,7 +21448,7 @@ mod tests {
listing_event_id.as_str(),
6,
);
- append_signed_order_request_record(
+ let request_event_id = append_signed_order_request_record(
&paths,
trade_order_id.as_str(),
listing_addr.as_str(),
@@ -21476,7 +21457,6 @@ mod tests {
seller_pubkey,
2,
);
- let request_event_id = signed_order_request_event_id(trade_order_id.as_str());
let decision_event_id = append_signed_order_decision_record(
&paths,
trade_order_id.as_str(),
@@ -21527,7 +21507,8 @@ mod tests {
String,
) {
let (runtime, paths) = bootstrapped_runtime(label);
- let (account_id, farm_id) = provision_ready_farmer_account(&runtime);
+ let (account_id, farm_id) =
+ provision_ready_farmer_account_from_secret(&runtime, SDK_TEST_SELLER_SECRET_KEY_HEX);
runtime.lock_state_mut().nostr_relay_urls = vec!["wss://relay.example".to_owned()];
let seller_pubkey = runtime
.lock_state()
@@ -21538,8 +21519,7 @@ mod tests {
.expect("selected seller account should resolve")
.public_identity
.public_key_hex;
- let buyer_pubkey =
- "1111111111111111111111111111111111111111111111111111111111111111".to_owned();
+ let buyer_pubkey = SDK_TEST_BUYER_PUBLIC_KEY_HEX.to_owned();
let product_id = ProductId::new();
let trade_order_id = "seller-order-decision-1";
let order_id = projected_order_id_from_trade_request(trade_order_id, buyer_pubkey.as_str());
@@ -21589,7 +21569,8 @@ mod tests {
String,
) {
let (runtime, paths) = bootstrapped_runtime(label);
- let (account_id, farm_id) = provision_ready_farmer_account(&runtime);
+ let (account_id, farm_id) =
+ provision_ready_farmer_account_from_secret(&runtime, SDK_TEST_SELLER_SECRET_KEY_HEX);
runtime.lock_state_mut().nostr_relay_urls = vec!["wss://relay.example".to_owned()];
let seller_pubkey = runtime
.lock_state()
@@ -21664,12 +21645,18 @@ mod tests {
)
};
let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
+ let request_event_id = runtime
+ .lock_state()
+ .resolve_seller_order_request_evidence(order_id)
+ .expect("seller request evidence should resolve")
+ .request_event
+ .id;
let payload = AppPublishPayload::OrderDecision(AppOrderDecisionPublishPayload {
context: AppPublishContext::new(account_id.clone(), "seller_order_decision"),
app_order_id: order_id,
farm_id,
trade_order_id: "seller-order-decision-1".to_owned(),
- request_event_id: signed_order_request_event_id("seller-order-decision-1"),
+ request_event_id,
listing_event_id: Some(signed_listing_event_id("seller-order-decision")),
listing_addr: format!("30402:{seller_pubkey}:{listing_key}"),
buyer_pubkey: buyer_pubkey.to_owned(),
@@ -21827,7 +21814,7 @@ mod tests {
buyer_pubkey: &str,
seller_pubkey: &str,
order_quantity: u32,
- ) {
+ ) -> String {
let database_path = paths
.shared_local_events_database_path()
.expect("shared local events path");
@@ -21860,6 +21847,14 @@ mod tests {
.into_wire_parts();
let record_id = format!("app:signed_event:order-request:{trade_order_id}");
let event_id = signed_event_id(record_id.as_str());
+ let event = test_event_from_parts(
+ record_id.as_str(),
+ event_id,
+ buyer_pubkey,
+ 1_774_000_010,
+ parts,
+ );
+ let stored_event_id = event.id.clone();
let relay_delivery_json = RelayDeliveryEvidence::acknowledged(
["wss://relay.example"],
["wss://relay.example"],
@@ -21878,28 +21873,31 @@ mod tests {
created_at_ms: 1_774_000_010_000,
inserted_at_ms: 1_774_000_010_001,
owner_account_id: None,
- owner_pubkey: Some(buyer_pubkey.to_owned()),
+ owner_pubkey: Some(event.author.clone()),
farm_id: None,
listing_addr: Some(listing_addr.to_owned()),
local_work_json: None,
- event_id: Some(event_id.clone()),
- event_kind: Some(i64::from(parts.kind)),
- event_pubkey: Some(buyer_pubkey.to_owned()),
- event_created_at: Some(1_774_000_010),
- event_tags_json: Some(json!(parts.tags)),
- event_content: Some(parts.content.clone()),
- event_sig: Some("signature".to_owned()),
+ event_id: Some(event.id.clone()),
+ event_kind: Some(i64::from(event.kind)),
+ event_pubkey: Some(event.author.clone()),
+ event_created_at: Some(i64::from(event.created_at)),
+ event_tags_json: Some(json!(event.tags.clone())),
+ event_content: Some(event.content.clone()),
+ event_sig: Some(event.sig.clone()),
raw_event_json: Some(json!({
- "id": event_id,
- "kind": parts.kind,
- "pubkey": buyer_pubkey,
- "content": parts.content
+ "id": event.id.clone(),
+ "kind": event.kind,
+ "pubkey": event.author.clone(),
+ "tags": event.tags.clone(),
+ "content": event.content.clone(),
+ "sig": event.sig.clone()
})),
outbox_status: PublishOutboxStatus::Acknowledged,
relay_set_fingerprint: Some("relay-set".to_owned()),
relay_delivery_json: Some(relay_delivery_json),
})
.expect("append signed order request");
+ stored_event_id
}
fn append_verified_signed_order_request_record(
@@ -22054,18 +22052,13 @@ mod tests {
.expect("order decision draft should build")
.into_wire_parts();
let record_id = format!("app:signed_event:order-decision:{trade_order_id}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
seller_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn append_signed_payment_record(
@@ -22131,18 +22124,13 @@ mod tests {
let parts = order_payment_record_event_build(&request_event_id, &prev_event_id, &payload)
.expect("payment recorded draft should build");
let record_id = format!("app:signed_event:payment:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
buyer_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn append_signed_settlement_decision_record(
@@ -22186,18 +22174,13 @@ mod tests {
order_settlement_decision_event_build(&request_event_id, &payment_event_id, &payload)
.expect("k3436 draft should build");
let record_id = format!("app:signed_event:k3436:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
seller_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn signed_payment_recorded_relay_event(
@@ -22383,18 +22366,13 @@ mod tests {
.expect("fulfillment update draft should build")
.into_wire_parts();
let record_id = format!("app:signed_event:fulfillment:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
seller_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn append_signed_order_cancellation_record_with_prev(
@@ -22424,18 +22402,13 @@ mod tests {
.expect("order cancellation draft should build")
.into_wire_parts();
let record_id = format!("app:signed_event:cancellation:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
buyer_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn append_signed_order_receipt_record_with_prev(
@@ -22468,18 +22441,13 @@ mod tests {
.expect("buyer receipt draft should build")
.into_wire_parts();
let record_id = format!("app:signed_event:receipt:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
buyer_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn append_signed_order_revision_proposal_record_with_prev(
@@ -22514,18 +22482,13 @@ mod tests {
.expect("order revision proposal draft should build")
.into_wire_parts();
let record_id = format!("app:signed_event:revision-proposal:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
seller_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn append_signed_order_revision_decision_record_with_prev(
@@ -22560,18 +22523,13 @@ mod tests {
.expect("order revision decision draft should build")
.into_wire_parts();
let record_id = format!("app:signed_event:revision-decision:{event_key}");
- let event_id = signed_event_id(record_id.as_str());
append_trade_signed_event_record(
paths,
record_id.as_str(),
- event_id.as_str(),
- i64::from(parts.kind),
buyer_pubkey,
listing_addr,
- json!(parts.tags),
- parts.content,
- );
- event_id
+ parts,
+ )
}
fn revision_test_order_items() -> Vec<RadrootsOrderItem> {
@@ -22623,13 +22581,10 @@ mod tests {
fn append_trade_signed_event_record(
paths: &AppDesktopRuntimePaths,
record_id: &str,
- event_id: &str,
- event_kind: i64,
event_pubkey: &str,
listing_addr: &str,
- event_tags_json: serde_json::Value,
- event_content: String,
- ) {
+ parts: WireEventParts,
+ ) -> String {
let database_path = paths
.shared_local_events_database_path()
.expect("shared local events path");
@@ -22640,6 +22595,15 @@ mod tests {
SqliteExecutor::open(database_path.as_path()).expect("open shared local events db");
let store = LocalEventsStore::new(executor);
store.migrate_up().expect("migrate shared local events");
+ let created_at = test_event_created_at(record_id, 1_774_000_020);
+ let event = test_event_from_parts(
+ record_id,
+ signed_event_id(record_id),
+ event_pubkey,
+ created_at,
+ parts,
+ );
+ let stored_event_id = event.id.clone();
let relay_delivery_json = RelayDeliveryEvidence::acknowledged(
["wss://relay.example"],
["wss://relay.example"],
@@ -22655,32 +22619,34 @@ mod tests {
family: LocalRecordFamily::SignedEvent,
status: LocalRecordStatus::Published,
source_runtime: SourceRuntime::Test,
- created_at_ms: 1_774_000_020_000,
- inserted_at_ms: 1_774_000_020_001,
+ created_at_ms: i64::from(created_at) * 1000,
+ inserted_at_ms: i64::from(created_at) * 1000 + 1,
owner_account_id: None,
- owner_pubkey: Some(event_pubkey.to_owned()),
+ owner_pubkey: Some(event.author.clone()),
farm_id: None,
listing_addr: Some(listing_addr.to_owned()),
local_work_json: None,
- event_id: Some(event_id.to_owned()),
- event_kind: Some(event_kind),
- event_pubkey: Some(event_pubkey.to_owned()),
- event_created_at: Some(1_774_000_020),
- event_tags_json: Some(event_tags_json.clone()),
- event_content: Some(event_content.clone()),
- event_sig: Some("signature".to_owned()),
+ event_id: Some(event.id.clone()),
+ event_kind: Some(i64::from(event.kind)),
+ event_pubkey: Some(event.author.clone()),
+ event_created_at: Some(i64::from(event.created_at)),
+ event_tags_json: Some(json!(event.tags.clone())),
+ event_content: Some(event.content.clone()),
+ event_sig: Some(event.sig.clone()),
raw_event_json: Some(json!({
- "id": event_id,
- "kind": event_kind,
- "pubkey": event_pubkey,
- "tags": event_tags_json,
- "content": event_content
+ "id": event.id.clone(),
+ "kind": event.kind,
+ "pubkey": event.author.clone(),
+ "tags": event.tags.clone(),
+ "content": event.content.clone(),
+ "sig": event.sig.clone()
})),
outbox_status: PublishOutboxStatus::Acknowledged,
relay_set_fingerprint: Some("relay-set".to_owned()),
relay_delivery_json: Some(relay_delivery_json),
})
.expect("append signed trade event");
+ stored_event_id
}
fn mark_shared_seller_order_request_evidence_pending(paths: &AppDesktopRuntimePaths) {
@@ -22898,6 +22864,18 @@ mod tests {
.expect("shared local records should list")
}
+ fn shared_order_request_event_id(
+ paths: &AppDesktopRuntimePaths,
+ trade_order_id: &str,
+ ) -> String {
+ let record_id = format!("app:signed_event:order-request:{trade_order_id}");
+ shared_local_event_records(paths)
+ .into_iter()
+ .find(|record| record.record_id == record_id)
+ .and_then(|record| record.event_id)
+ .expect("signed order request event id should exist")
+ }
+
fn shared_order_events_by_kind(
paths: &AppDesktopRuntimePaths,
kind: i64,
@@ -22917,20 +22895,6 @@ mod tests {
.collect()
}
- fn event_has_tag(event: &SdkRadrootsNostrEvent, key: &str, value: &str) -> bool {
- event.tags.iter().any(|tag| {
- tag.first().map(String::as_str) == Some(key)
- && tag.get(1).map(String::as_str) == Some(value)
- })
- }
-
- fn event_has_nonempty_value_tag(event: &SdkRadrootsNostrEvent, key: &str) -> bool {
- event.tags.iter().any(|tag| {
- tag.first().map(String::as_str) == Some(key)
- && tag.get(1).map(|value| !value.is_empty()).unwrap_or(false)
- })
- }
-
fn persisted_order_status(runtime: &DesktopAppRuntime, order_id: OrderId) -> String {
runtime
.lock_state()
@@ -23054,6 +23018,96 @@ mod tests {
}
}
+ fn assert_order_revision_decision_sdk_migration_receipt(
+ runtime: &DesktopAppRuntime,
+ order_id: OrderId,
+ revision_id: &str,
+ expected_state: AppSdkMigrationState,
+ ) {
+ assert_order_sdk_migration_receipt(
+ runtime,
+ format!("app:order_revision_decision:{order_id}:{revision_id}").as_str(),
+ ORDER_REVISION_DECISION_OPERATION_KIND,
+ expected_state,
+ );
+ }
+
+ fn assert_order_cancellation_sdk_migration_receipt(
+ runtime: &DesktopAppRuntime,
+ order_id: OrderId,
+ expected_state: AppSdkMigrationState,
+ ) {
+ assert_order_sdk_migration_receipt(
+ runtime,
+ format!("app:order_cancellation:{order_id}").as_str(),
+ ORDER_CANCELLATION_OPERATION_KIND,
+ expected_state,
+ );
+ }
+
+ fn assert_order_fulfillment_sdk_migration_receipt(
+ runtime: &DesktopAppRuntime,
+ order_id: OrderId,
+ fulfillment: RadrootsOrderFulfillmentState,
+ expected_state: AppSdkMigrationState,
+ ) {
+ assert_order_sdk_migration_receipt(
+ runtime,
+ format!(
+ "app:order_fulfillment:{order_id}:{}",
+ order_fulfillment_status_storage_key(fulfillment)
+ )
+ .as_str(),
+ ORDER_FULFILLMENT_UPDATE_OPERATION_KIND,
+ expected_state,
+ );
+ }
+
+ fn assert_order_receipt_sdk_migration_receipt(
+ runtime: &DesktopAppRuntime,
+ order_id: OrderId,
+ expected_state: AppSdkMigrationState,
+ ) {
+ assert_order_sdk_migration_receipt(
+ runtime,
+ format!("app:order_receipt:{order_id}").as_str(),
+ ORDER_RECEIPT_RECORD_OPERATION_KIND,
+ expected_state,
+ );
+ }
+
+ fn assert_order_sdk_migration_receipt(
+ runtime: &DesktopAppRuntime,
+ source_record_id: &str,
+ operation_kind: &str,
+ expected_state: AppSdkMigrationState,
+ ) {
+ let receipt = runtime
+ .lock_state()
+ .sqlite_store
+ .as_ref()
+ .expect("sqlite store")
+ .sdk_migration_receipt_repository()
+ .load_receipt(
+ AppSdkMigrationReceiptSourceKind::LocalOutbox,
+ source_record_id,
+ )
+ .expect("SDK migration receipt should load")
+ .expect("SDK migration receipt should exist");
+ assert_eq!(receipt.source_record_id, source_record_id);
+ assert_eq!(receipt.sdk_operation_kind, operation_kind);
+ assert_eq!(
+ receipt.migration_state, expected_state,
+ "receipt detail: {}",
+ receipt.detail_json
+ );
+ if expected_state == AppSdkMigrationState::Enqueued {
+ assert!(receipt.expected_event_id.is_some());
+ assert!(receipt.actor_pubkey.as_deref().is_some_and(is_hex_64));
+ assert!(!receipt.sdk_outbox_event_ids.is_empty());
+ }
+ }
+
fn buyer_order_local_work_record_ids(paths: &AppDesktopRuntimePaths) -> Vec<String> {
shared_local_event_records(paths)
.into_iter()
@@ -23444,6 +23498,24 @@ mod tests {
.generate_local_account(Some("Farmer".to_owned()))
.expect("account should generate")
);
+ provision_selected_farmer_account(runtime)
+ }
+
+ fn provision_ready_farmer_account_from_secret(
+ runtime: &DesktopAppRuntime,
+ secret_key_hex: &str,
+ ) -> (String, FarmId) {
+ assert!(
+ runtime
+ .import_local_account(DesktopLocalIdentityImportRequest::raw_secret_key(
+ secret_key_hex,
+ ))
+ .expect("account should import")
+ );
+ provision_selected_farmer_account(runtime)
+ }
+
+ fn provision_selected_farmer_account(runtime: &DesktopAppRuntime) -> (String, FarmId) {
let account_id = runtime
.summary()
.settings_account_projection