@@ -894,6 +894,7 @@ pub mod tests {
894894 } ,
895895 } ;
896896 use bcr_ebill_core:: { application:: nostr_contact:: HandshakeStatus , protocol:: crypto:: BcrKeys } ;
897+ use bcr_ebill_persistence:: PendingContactShare ;
897898 use std:: collections:: HashMap ;
898899
899900 pub fn get_baseline_contact ( ) -> Contact {
@@ -1514,4 +1515,277 @@ pub mod tests {
15141515 assert ! ( result. is_ok( ) ) ;
15151516 assert ! ( result. as_ref( ) . unwrap( ) ) ;
15161517 }
1518+
1519+ fn pending_contact_share ( pending_share_id : & str ) -> PendingContactShare {
1520+ PendingContactShare {
1521+ id : pending_share_id. to_string ( ) ,
1522+ node_id : node_id_test_other ( ) ,
1523+ contact : get_baseline_contact ( ) ,
1524+ sender_node_id : node_id_test ( ) ,
1525+ contact_private_key : BcrKeys :: new ( ) . get_private_key ( ) ,
1526+ receiver_node_id : node_id_test ( ) ,
1527+ received_at : bcr_ebill_core:: protocol:: Timestamp :: now ( ) ,
1528+ direction : bcr_ebill_persistence:: ShareDirection :: Incoming ,
1529+ initial_share_id : Some ( "initial_id" . to_string ( ) ) ,
1530+ }
1531+ }
1532+
1533+ #[ tokio:: test]
1534+ async fn approve_contact_share_adds_contact_without_share_back ( ) {
1535+ init_test_cfg ( ) ;
1536+ let (
1537+ mut store,
1538+ file_upload_store,
1539+ file_upload_client,
1540+ identity_store,
1541+ company_store,
1542+ mut nostr_contact,
1543+ transport,
1544+ ) = get_storages ( ) ;
1545+
1546+ let pending_share_id = "test_share_id" ;
1547+ let pending_share = pending_contact_share ( pending_share_id) ;
1548+ let shared_node_id = pending_share. node_id . clone ( ) ;
1549+
1550+ // Mock getting the pending share
1551+ nostr_contact
1552+ . expect_get_pending_share ( )
1553+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1554+ . returning ( move |_| Ok ( Some ( pending_share. clone ( ) ) ) ) ;
1555+
1556+ // Expect contact to be inserted
1557+ store
1558+ . expect_get ( )
1559+ . with ( mockall:: predicate:: eq ( shared_node_id. clone ( ) ) )
1560+ . returning ( |_| Ok ( None ) ) ;
1561+ store. expect_insert ( ) . returning ( |_, _| Ok ( ( ) ) ) . once ( ) ;
1562+
1563+ // Expect NostrContact to be upserted
1564+ nostr_contact
1565+ . expect_by_node_id ( )
1566+ . returning ( |_| Ok ( None ) )
1567+ . once ( ) ;
1568+ nostr_contact. expect_upsert ( ) . returning ( |_| Ok ( ( ) ) ) . once ( ) ;
1569+
1570+ // Expect pending share to be deleted
1571+ nostr_contact
1572+ . expect_delete_pending_share ( )
1573+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1574+ . returning ( |_| Ok ( ( ) ) )
1575+ . once ( ) ;
1576+
1577+ let service = get_service (
1578+ store,
1579+ file_upload_store,
1580+ file_upload_client,
1581+ identity_store,
1582+ company_store,
1583+ nostr_contact,
1584+ transport,
1585+ ) ;
1586+
1587+ let result = service
1588+ . approve_contact_share ( pending_share_id, true , false )
1589+ . await ;
1590+
1591+ assert ! ( result. is_ok( ) ) ;
1592+ }
1593+
1594+ #[ tokio:: test]
1595+ async fn approve_contact_share_adds_contact_with_share_back ( ) {
1596+ init_test_cfg ( ) ;
1597+ let (
1598+ mut store,
1599+ file_upload_store,
1600+ file_upload_client,
1601+ mut identity_store,
1602+ company_store,
1603+ mut nostr_contact,
1604+ mut transport,
1605+ ) = get_storages ( ) ;
1606+
1607+ let receiver_identity = get_baseline_identity ( ) ;
1608+
1609+ let pending_share_id = "test_share_id" ;
1610+ let pending_share = pending_contact_share ( pending_share_id) ;
1611+ let shared_node_id = pending_share. node_id . clone ( ) ;
1612+
1613+ // Mock getting the pending share
1614+ nostr_contact
1615+ . expect_get_pending_share ( )
1616+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1617+ . returning ( move |_| Ok ( Some ( pending_share. clone ( ) ) ) ) ;
1618+
1619+ // Expect contact to be inserted
1620+ store
1621+ . expect_get ( )
1622+ . with ( mockall:: predicate:: eq ( shared_node_id. clone ( ) ) )
1623+ . returning ( |_| Ok ( None ) ) ;
1624+ store. expect_insert ( ) . returning ( |_, _| Ok ( ( ) ) ) . once ( ) ;
1625+
1626+ // Expect NostrContact to be upserted
1627+ nostr_contact
1628+ . expect_by_node_id ( )
1629+ . returning ( |_| Ok ( None ) )
1630+ . once ( ) ;
1631+ nostr_contact. expect_upsert ( ) . returning ( |_| Ok ( ( ) ) ) . once ( ) ;
1632+
1633+ // Expect pending share to be deleted
1634+ nostr_contact
1635+ . expect_delete_pending_share ( )
1636+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1637+ . returning ( |_| Ok ( ( ) ) )
1638+ . once ( ) ;
1639+
1640+ // Expect identity to be fetched for share back
1641+ identity_store
1642+ . expect_get_full ( )
1643+ . returning ( move || Ok ( receiver_identity. clone ( ) ) )
1644+ . once ( ) ;
1645+
1646+ // Share back will use identity since receiver_node_id matches identity.node_id
1647+ // So company_store.exists() will NOT be called
1648+
1649+ // Expect share back to be called
1650+ let mut contact_transport =
1651+ crate :: service:: transport_service:: MockContactTransportServiceApi :: new ( ) ;
1652+ contact_transport
1653+ . expect_share_contact_details_keys ( )
1654+ . times ( 1 )
1655+ . returning ( |_, _, _, _| Ok ( ( ) ) ) ;
1656+ transport
1657+ . expect_contact_transport ( )
1658+ . times ( 1 )
1659+ . return_const ( Arc :: new ( contact_transport) ) ;
1660+
1661+ let service = get_service (
1662+ store,
1663+ file_upload_store,
1664+ file_upload_client,
1665+ identity_store,
1666+ company_store,
1667+ nostr_contact,
1668+ transport,
1669+ ) ;
1670+
1671+ let result = service
1672+ . approve_contact_share ( pending_share_id, true , true )
1673+ . await ;
1674+
1675+ assert ! ( result. is_ok( ) ) ;
1676+ }
1677+
1678+ #[ tokio:: test]
1679+ async fn approve_contact_share_shares_back_without_adding_contact ( ) {
1680+ init_test_cfg ( ) ;
1681+ let (
1682+ store,
1683+ file_upload_store,
1684+ file_upload_client,
1685+ mut identity_store,
1686+ company_store,
1687+ mut nostr_contact,
1688+ mut transport,
1689+ ) = get_storages ( ) ;
1690+
1691+ let receiver_identity = get_baseline_identity ( ) ;
1692+ let pending_share_id = "test_share_id" ;
1693+ let pending_share = pending_contact_share ( pending_share_id) ;
1694+
1695+ // Mock getting the pending share
1696+ nostr_contact
1697+ . expect_get_pending_share ( )
1698+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1699+ . returning ( move |_| Ok ( Some ( pending_share. clone ( ) ) ) ) ;
1700+
1701+ // Expect pending share to be deleted
1702+ nostr_contact
1703+ . expect_delete_pending_share ( )
1704+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1705+ . returning ( |_| Ok ( ( ) ) )
1706+ . once ( ) ;
1707+
1708+ // Expect identity to be fetched for share back
1709+ identity_store
1710+ . expect_get_full ( )
1711+ . returning ( move || Ok ( receiver_identity. clone ( ) ) )
1712+ . once ( ) ;
1713+
1714+ // Share back will use identity since receiver_node_id matches identity.node_id
1715+ // So company_store.exists() will NOT be called
1716+
1717+ // Expect share back to be called
1718+ let mut contact_transport =
1719+ crate :: service:: transport_service:: MockContactTransportServiceApi :: new ( ) ;
1720+ contact_transport
1721+ . expect_share_contact_details_keys ( )
1722+ . times ( 1 )
1723+ . returning ( |_, _, _, _| Ok ( ( ) ) ) ;
1724+ transport
1725+ . expect_contact_transport ( )
1726+ . times ( 1 )
1727+ . return_const ( Arc :: new ( contact_transport) ) ;
1728+
1729+ let service = get_service (
1730+ store,
1731+ file_upload_store,
1732+ file_upload_client,
1733+ identity_store,
1734+ company_store,
1735+ nostr_contact,
1736+ transport,
1737+ ) ;
1738+
1739+ let result = service
1740+ . approve_contact_share ( pending_share_id, false , true )
1741+ . await ;
1742+
1743+ assert ! ( result. is_ok( ) ) ;
1744+ }
1745+
1746+ #[ tokio:: test]
1747+ async fn approve_contact_share_does_nothing_when_both_false ( ) {
1748+ init_test_cfg ( ) ;
1749+ let (
1750+ store,
1751+ file_upload_store,
1752+ file_upload_client,
1753+ identity_store,
1754+ company_store,
1755+ mut nostr_contact,
1756+ transport,
1757+ ) = get_storages ( ) ;
1758+
1759+ let pending_share_id = "test_share_id" ;
1760+ let pending_share = pending_contact_share ( pending_share_id) ;
1761+
1762+ // Mock getting the pending share
1763+ nostr_contact
1764+ . expect_get_pending_share ( )
1765+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1766+ . returning ( move |_| Ok ( Some ( pending_share. clone ( ) ) ) ) ;
1767+
1768+ // Expect pending share to be deleted (only operation that should happen)
1769+ nostr_contact
1770+ . expect_delete_pending_share ( )
1771+ . with ( mockall:: predicate:: eq ( pending_share_id) )
1772+ . returning ( |_| Ok ( ( ) ) )
1773+ . once ( ) ;
1774+
1775+ let service = get_service (
1776+ store,
1777+ file_upload_store,
1778+ file_upload_client,
1779+ identity_store,
1780+ company_store,
1781+ nostr_contact,
1782+ transport,
1783+ ) ;
1784+
1785+ let result = service
1786+ . approve_contact_share ( pending_share_id, false , false )
1787+ . await ;
1788+
1789+ assert ! ( result. is_ok( ) ) ;
1790+ }
15171791}
0 commit comments