Skip to content

Commit be0b6f2

Browse files
committed
added more test coverage for optional user id \n improved comment syntax and meaning
1 parent 4dfb470 commit be0b6f2

File tree

5 files changed

+163
-49
lines changed

5 files changed

+163
-49
lines changed

teos/proto/teos/v2/appointment.proto

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ package teos.v2;
44
import "common/teos/v2/appointment.proto";
55

66
message GetAppointmentsRequest {
7-
// Request the information of appointments with specific locator and user_id (optional) .
7+
// Request the information of appointments with specific locator.
8+
// If a user id is provided (optional), request only appointments belonging to that user.
89

910
bytes locator = 1;
1011
optional bytes user_id = 2;

teos/src/api/internal.rs

Lines changed: 116 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -298,26 +298,23 @@ impl PrivateTowerServices for Arc<InternalAPI> {
298298
)
299299
})?;
300300

301-
let appointments: Vec<Appointment> = self
301+
let mut matching_appointments: Vec<common_msgs::AppointmentData> = self
302302
.watcher
303303
.get_watcher_appointments_with_locator(locator, user_id)
304304
.into_values()
305-
.map(|appointment| appointment.inner)
306-
.collect();
307-
308-
let mut matching_appointments: Vec<common_msgs::AppointmentData> = appointments
309-
.into_iter()
310305
.map(|appointment| common_msgs::AppointmentData {
311306
appointment_data: Some(
312-
common_msgs::appointment_data::AppointmentData::Appointment(appointment.into()),
307+
common_msgs::appointment_data::AppointmentData::Appointment(
308+
appointment.inner.into(),
309+
),
313310
),
314311
})
315312
.collect();
316313

317-
for (_, tracker) in self
314+
for tracker in self
318315
.watcher
319316
.get_responder_trackers_with_locator(locator, user_id)
320-
.into_iter()
317+
.into_values()
321318
{
322319
matching_appointments.push(common_msgs::AppointmentData {
323320
appointment_data: Some(common_msgs::appointment_data::AppointmentData::Tracker(
@@ -445,6 +442,8 @@ mod tests_private_api {
445442
use bitcoin::hashes::Hash;
446443
use bitcoin::Txid;
447444

445+
use rand::{self, thread_rng, Rng};
446+
448447
use crate::responder::{ConfirmationStatus, TransactionTracker};
449448
use crate::test_utils::{
450449
create_api, generate_dummy_appointment, generate_dummy_appointment_with_user,
@@ -453,7 +452,7 @@ mod tests_private_api {
453452
use crate::watcher::Breach;
454453

455454
use teos_common::cryptography::{self, get_random_keypair};
456-
use teos_common::test_utils::get_random_user_id;
455+
use teos_common::test_utils::{get_random_locator, get_random_user_id};
457456

458457
#[tokio::test]
459458
async fn test_get_all_appointments() {
@@ -531,18 +530,33 @@ mod tests_private_api {
531530
.into_inner();
532531

533532
assert!(matches!(response, msgs::GetAppointmentsResponse { .. }));
533+
534+
let user_id = get_random_user_id().to_vec();
535+
let locator = get_random_locator().to_vec();
536+
let response = internal_api
537+
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
538+
locator,
539+
user_id: Some(user_id),
540+
}))
541+
.await
542+
.unwrap()
543+
.into_inner();
544+
545+
assert!(matches!(response, msgs::GetAppointmentsResponse { .. }));
534546
}
535547

536548
#[tokio::test]
537-
async fn test_get_appointments_watcher() {
549+
async fn test_get_appointments_watcher_without_userid() {
538550
let (internal_api, _s) = create_api().await;
539551

540552
for i in 0..3 {
541553
// Create a dispute tx to be used for creating different dummy appointments with the same locator.
542554
let dispute_txid = get_random_tx().txid();
555+
let locator = Locator::new(dispute_txid);
543556

544557
// The number of different appointments to create for this dispute tx.
545-
let appointments_to_create = 4 * i + 7;
558+
let random_number = 4 * i + 7;
559+
let appointments_to_create = random_number;
546560

547561
// Add that many appointments to the watcher.
548562
for _ in 0..appointments_to_create {
@@ -556,8 +570,6 @@ mod tests_private_api {
556570
.unwrap();
557571
}
558572

559-
let locator = Locator::new(dispute_txid);
560-
561573
// Query for the current locator and assert it retrieves correct appointments.
562574
let response = internal_api
563575
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
@@ -584,6 +596,62 @@ mod tests_private_api {
584596
}
585597
}
586598

599+
#[tokio::test]
600+
async fn test_get_appointments_watcher_with_userid() {
601+
let (internal_api, _s) = create_api().await;
602+
603+
for i in 0..3 {
604+
// Create a dispute tx to be used for creating different dummy appointments with the same locator.
605+
let dispute_txid = get_random_tx().txid();
606+
let locator = Locator::new(dispute_txid);
607+
608+
// The number of different appointments to create for this dispute tx.
609+
let random_number = 4 * i + 7;
610+
let appointments_to_create = random_number;
611+
612+
let mut random_users_list = Vec::new();
613+
614+
// Add that many appointments to the watcher.
615+
for _ in 0..appointments_to_create {
616+
let (user_sk, user_pk) = get_random_keypair();
617+
let user_id = UserId(user_pk);
618+
internal_api.watcher.register(user_id).unwrap();
619+
random_users_list.push(user_id);
620+
let appointment = generate_dummy_appointment(Some(&dispute_txid)).inner;
621+
let signature = cryptography::sign(&appointment.to_vec(), &user_sk).unwrap();
622+
internal_api
623+
.watcher
624+
.add_appointment(appointment, signature)
625+
.unwrap();
626+
}
627+
628+
for user_id in random_users_list.into_iter() {
629+
let response = internal_api
630+
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
631+
locator: locator.to_vec(),
632+
user_id: Some(user_id.to_vec()),
633+
}))
634+
.await
635+
.unwrap()
636+
.into_inner();
637+
638+
// Verify that only a single appointment is returned
639+
assert_eq!(response.appointments.len(), 1);
640+
641+
// Verify that the appointment have the current locator
642+
assert!(matches!(
643+
response.appointments[0].appointment_data,
644+
Some(common_msgs::appointment_data::AppointmentData::Appointment(
645+
common_msgs::Appointment {
646+
locator: ref app_loc,
647+
..
648+
}
649+
)) if Locator::from_slice(app_loc).unwrap() == locator
650+
));
651+
}
652+
}
653+
}
654+
587655
#[tokio::test]
588656
async fn test_get_appointments_responder() {
589657
let (internal_api, _s) = create_api().await;
@@ -596,11 +664,19 @@ mod tests_private_api {
596664
// The number of different trackers to create for this dispute tx.
597665
let trackers_to_create = 4 * i + 7;
598666

667+
let random_tracker_num = thread_rng().gen_range(0..trackers_to_create);
668+
let random_user_id = get_random_user_id();
669+
599670
// Add that many trackers to the responder.
600-
for _ in 0..trackers_to_create {
671+
for i in 0..trackers_to_create {
672+
let user_id = if i == random_tracker_num {
673+
random_user_id
674+
} else {
675+
get_random_user_id()
676+
};
601677
let tracker = TransactionTracker::new(
602678
breach.clone(),
603-
get_random_user_id(),
679+
user_id,
604680
ConfirmationStatus::ConfirmedIn(100),
605681
);
606682
internal_api
@@ -610,7 +686,7 @@ mod tests_private_api {
610686

611687
let locator = Locator::new(dispute_tx.txid());
612688

613-
// Query for the current locator and assert it retrieves correct trackers.
689+
// Query for the current locator without the optional user_id.
614690
let response = internal_api
615691
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
616692
locator: locator.to_vec(),
@@ -620,7 +696,7 @@ mod tests_private_api {
620696
.unwrap()
621697
.into_inner();
622698

623-
// The response should contain `trackers_to_create` trackers, all with dispute txid that matches with the locator of the current iteration.
699+
// Verify that the response should contain `trackers_to_create` trackers, all with dispute txid that matches with the locator of the current iteration.
624700
assert_eq!(response.appointments.len(), trackers_to_create);
625701
for app_data in response.appointments {
626702
assert!(matches!(
@@ -633,6 +709,28 @@ mod tests_private_api {
633709
)) if Locator::new(Txid::from_slice(dispute_txid).unwrap()) == locator
634710
));
635711
}
712+
713+
// Query for the current locator with the optional user_id present.
714+
let response = internal_api
715+
.get_appointments(Request::new(msgs::GetAppointmentsRequest {
716+
locator: locator.to_vec(),
717+
user_id: Some(random_user_id.to_vec()),
718+
}))
719+
.await
720+
.unwrap()
721+
.into_inner();
722+
723+
// Verify that only a single appointment is returned and the correct locator is found
724+
assert_eq!(response.appointments.len(), 1);
725+
assert!(matches!(
726+
response.appointments[0].appointment_data,
727+
Some(common_msgs::appointment_data::AppointmentData::Tracker(
728+
common_msgs::Tracker {
729+
ref dispute_txid,
730+
..
731+
}
732+
)) if Locator::new(Txid::from_slice(dispute_txid).unwrap()) == locator
733+
));
636734
}
637735
}
638736

teos/src/dbm.rs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,15 @@ impl DBM {
338338
"SELECT a.UUID, a.locator, a.encrypted_blob, a.to_self_delay, a.user_signature, a.start_block, a.user_id
339339
FROM appointments as a LEFT JOIN trackers as t ON a.UUID=t.UUID WHERE t.UUID IS NULL".to_string();
340340

341-
// If a locator and an optional user_id were passed, filter based on it.
342-
if let Some((_, user_id)) = locator_and_userid {
341+
// If a locator was passed, filter based on it.
342+
if locator_and_userid.is_some() {
343343
sql.push_str(" AND a.locator=(?1)");
344-
if user_id.is_some() {
345-
sql.push_str(" AND a.user_id=(?2)");
346-
}
347-
};
344+
}
345+
346+
// If a user_id is passed, filter even more.
347+
if locator_and_userid.is_some_and(|inner| inner.1.is_some()) {
348+
sql.push_str(" AND a.user_id=(?2)");
349+
}
348350

349351
let mut stmt = self.connection.prepare(&sql).unwrap();
350352

@@ -611,12 +613,14 @@ impl DBM {
611613
FROM trackers as t INNER JOIN appointments as a ON t.UUID=a.UUID"
612614
.to_string();
613615

614-
// If a locator and an optional user_id were passed, filter based on it.
615-
if let Some((_, user_id)) = locator_and_userid {
616+
// If a locator was passed, filter based on it.
617+
if locator_and_userid.is_some() {
616618
sql.push_str(" AND a.locator=(?1)");
617-
if user_id.is_some() {
618-
sql.push_str(" AND a.user_id=(?2)");
619-
}
619+
}
620+
621+
// If a user_id is passed, filter even more.
622+
if locator_and_userid.is_some_and(|inner| inner.1.is_some()) {
623+
sql.push_str(" AND a.user_id=(?2)");
620624
}
621625

622626
let mut stmt = self.connection.prepare(&sql).unwrap();
@@ -774,8 +778,8 @@ mod tests {
774778

775779
use crate::rpc_errors;
776780
use crate::test_utils::{
777-
generate_dummy_appointment, generate_dummy_appointment_with_user, generate_uuid,
778-
get_random_tracker, get_random_tx, AVAILABLE_SLOTS, SUBSCRIPTION_EXPIRY,
781+
generate_dummy_appointment, generate_dummy_appointment_with_user, generate_dummy_tracker,
782+
generate_uuid, get_random_tracker, get_random_tx, AVAILABLE_SLOTS, SUBSCRIPTION_EXPIRY,
779783
SUBSCRIPTION_START,
780784
};
781785

@@ -1201,7 +1205,7 @@ mod tests {
12011205
let dispute_txid = dispute_tx.txid();
12021206
let locator = Locator::new(dispute_txid);
12031207

1204-
// create user id
1208+
// Create user id
12051209
let user_id = get_random_user_id();
12061210
let user = UserInfo::new(AVAILABLE_SLOTS, SUBSCRIPTION_START, SUBSCRIPTION_EXPIRY);
12071211
dbm.store_user(user_id, &user).unwrap();
@@ -1212,14 +1216,14 @@ mod tests {
12121216
dbm.store_appointment(uuid, &appointment).unwrap();
12131217
appointments.insert(uuid, appointment.clone());
12141218

1215-
// create random appointments
1219+
// Create random appointments
12161220
for _ in 1..11 {
12171221
let (uuid, appointment) = generate_dummy_appointment_with_user(user_id, None);
12181222
dbm.store_appointment(uuid, &appointment).unwrap();
12191223
appointments.insert(uuid, appointment);
12201224
}
12211225

1222-
// Returns empty if no appointment matches both userid and locator
1226+
// Verify that no appointment is returned if there is not an exact match of user_id + locator
12231227
assert_eq!(
12241228
dbm.load_appointments(Some((locator, Some(get_random_user_id()))),),
12251229
HashMap::new()
@@ -1229,17 +1233,17 @@ mod tests {
12291233
HashMap::new()
12301234
);
12311235

1232-
// Returns particular appointments if they match both userid and locator
1236+
// Verify that the expected appointment is returned, if the correct user_id and locator is given
12331237
assert_eq!(
12341238
dbm.load_appointments(Some((locator, Some(user_id))),),
12351239
HashMap::from([(uuid, appointment)])
12361240
);
12371241

1238-
// Create a tracker from existing appointment
1239-
let tracker = get_random_tracker(user_id, ConfirmationStatus::InMempoolSince(100));
1242+
// Create a tracker from the existing appointment
1243+
let tracker = generate_dummy_tracker(user_id, dispute_tx.clone());
12401244
dbm.store_tracker(uuid, &tracker).unwrap();
12411245

1242-
// ensure that no tracker is returned
1246+
// Verify that an appointment is not returned, if it is triggered (there's a tracker for it)
12431247
assert_eq!(
12441248
dbm.load_appointments(Some((locator, Some(user_id))),),
12451249
HashMap::new()
@@ -1622,30 +1626,29 @@ mod tests {
16221626
let dispute_tx = get_random_tx();
16231627
let dispute_txid = dispute_tx.txid();
16241628
let locator = Locator::new(dispute_txid);
1625-
let status = ConfirmationStatus::InMempoolSince(42);
16261629

1627-
// create user id
1630+
// Create user id
16281631
let user_id = get_random_user_id();
16291632
let user = UserInfo::new(AVAILABLE_SLOTS, SUBSCRIPTION_START, SUBSCRIPTION_EXPIRY);
16301633
dbm.store_user(user_id, &user).unwrap();
16311634

16321635
// Create and store a particular tracker
16331636
let (uuid, appointment) =
16341637
generate_dummy_appointment_with_user(user_id, Some(&dispute_txid));
1635-
let tracker = get_random_tracker(user_id, status);
1638+
let tracker = generate_dummy_tracker(user_id, dispute_tx.clone());
16361639
dbm.store_appointment(uuid, &appointment).unwrap();
16371640
dbm.store_tracker(uuid, &tracker).unwrap();
16381641
trackers.insert(uuid, tracker.clone());
16391642

1640-
// create random trackers
1643+
// Create random trackers
16411644
for _ in 1..11 {
16421645
let (uuid, appointment) = generate_dummy_appointment_with_user(user_id, None);
1643-
let tracker = get_random_tracker(user_id, status);
1646+
let tracker = generate_dummy_tracker(user_id, dispute_tx.clone());
16441647
dbm.store_appointment(uuid, &appointment).unwrap();
16451648
dbm.store_tracker(uuid, &tracker).unwrap();
16461649
}
16471650

1648-
// Returns empty if no tracker matches both userid and locator
1651+
// Verify that no tracker is returned if there is not an exact match of user_id + locator
16491652
assert_eq!(
16501653
dbm.load_trackers(Some((locator, Some(get_random_user_id()))),),
16511654
HashMap::new()
@@ -1655,7 +1658,7 @@ mod tests {
16551658
HashMap::new()
16561659
);
16571660

1658-
// Returns particular trackers if they match both userid and locator
1661+
// Verify that the expected tracker is returned if both the correct user_id and locator are provided
16591662
assert_eq!(
16601663
dbm.load_trackers(Some((locator, Some(user_id))),),
16611664
HashMap::from([(uuid, tracker)])

0 commit comments

Comments
 (0)