@@ -806,6 +806,7 @@ func TestAddContractListenerInline(t *testing.T) {
806806 mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
807807 mbi .On ("AddContractListener" , context .Background (), & sub .ContractListener , "" ).Return (nil )
808808 mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
809+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .Anything ).Return (nil )
809810
810811 result , err := cm .AddContractListener (context .Background (), sub )
811812 assert .NoError (t , err )
@@ -847,6 +848,7 @@ func TestAddContractListenerInlineNilLocation(t *testing.T) {
847848 return cl .Location == nil
848849 }), "" ).Return (nil )
849850 mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
851+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .Anything ).Return (nil )
850852
851853 result , err := cm .AddContractListener (context .Background (), sub )
852854 assert .NoError (t , err )
@@ -885,6 +887,7 @@ func TestAddContractListenerNoLocationOK(t *testing.T) {
885887 mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
886888 mbi .On ("AddContractListener" , context .Background (), & sub .ContractListener , "" ).Return (nil )
887889 mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
890+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .Anything ).Return (nil )
888891
889892 result , err := cm .AddContractListener (context .Background (), sub )
890893 assert .NoError (t , err )
@@ -937,6 +940,7 @@ func TestAddContractListenerByEventPath(t *testing.T) {
937940 mdi .On ("GetFFIByID" , context .Background (), "ns1" , interfaceID ).Return (& fftypes.FFI {}, nil )
938941 mdi .On ("GetFFIEvent" , context .Background (), "ns1" , interfaceID , sub .EventPath ).Return (event , nil )
939942 mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
943+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .Anything ).Return (nil )
940944
941945 result , err := cm .AddContractListener (context .Background (), sub )
942946 assert .NoError (t , err )
@@ -1648,7 +1652,10 @@ func TestAddContractListenerBlockchainFail(t *testing.T) {
16481652 mbi .On ("GenerateEventSignature" , context .Background (), mock .Anything ).Return ("changed" , nil )
16491653 mbi .On ("GenerateEventSignatureWithLocation" , context .Background (), mock .Anything , mock .Anything ).Return ("0x123:changed" , nil )
16501654 mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
1655+ mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
16511656 mbi .On ("AddContractListener" , context .Background (), & sub .ContractListener , "" ).Return (fmt .Errorf ("pop" ))
1657+ // The connector failure compensates by deleting the row inserted above
1658+ mdi .On ("DeleteContractListenerByID" , context .Background (), "ns1" , mock .Anything ).Return (nil )
16521659
16531660 _ , err := cm .AddContractListener (context .Background (), sub )
16541661 assert .EqualError (t , err , "pop" )
@@ -1686,8 +1693,181 @@ func TestAddContractListenerUpsertSubFail(t *testing.T) {
16861693 mbi .On ("GenerateEventSignature" , context .Background (), mock .Anything ).Return ("changed" , nil )
16871694 mbi .On ("GenerateEventSignatureWithLocation" , context .Background (), mock .Anything , mock .Anything ).Return ("0x123:changed" , nil )
16881695 mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
1689- mbi .On ("AddContractListener" , context .Background (), & sub .ContractListener , "" ).Return (nil )
16901696 mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (fmt .Errorf ("pop" ))
1697+ mdi .On ("GetContractListener" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil )
1698+
1699+ _ , err := cm .AddContractListener (context .Background (), sub )
1700+ assert .EqualError (t , err , "pop" )
1701+
1702+ mbi .AssertExpectations (t )
1703+ mdi .AssertExpectations (t )
1704+ }
1705+
1706+ func TestAddContractListenerInsertNameRace (t * testing.T ) {
1707+ cm := newTestContractManager ()
1708+ mbi := cm .blockchain .(* blockchainmocks.Plugin )
1709+ mdi := cm .database .(* databasemocks.Plugin )
1710+
1711+ sub := & core.ContractListenerInput {
1712+ ContractListener : core.ContractListener {
1713+ Name : "sub1" ,
1714+ Location : fftypes .JSONAnyPtr (fftypes.JSONObject {
1715+ "address" : "0x123" ,
1716+ }.String ()),
1717+ Event : & core.FFISerializedEvent {
1718+ FFIEventDefinition : fftypes.FFIEventDefinition {
1719+ Name : "changed" ,
1720+ Params : fftypes.FFIParams {
1721+ {
1722+ Name : "value" ,
1723+ Schema : fftypes .JSONAnyPtr (`{"type": "integer"}` ),
1724+ },
1725+ },
1726+ },
1727+ },
1728+ Topic : "test-topic" ,
1729+ },
1730+ }
1731+
1732+ mbi .On ("NormalizeContractLocation" , context .Background (), blockchain .NormalizeListener , sub .Location ).Return (sub .Location , nil )
1733+ mbi .On ("GenerateEventSignature" , context .Background (), mock .Anything ).Return ("changed" , nil )
1734+ mbi .On ("GenerateEventSignatureWithLocation" , context .Background (), mock .Anything , mock .Anything ).Return ("0x123:changed" , nil )
1735+ mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
1736+ mdi .On ("GetContractListener" , context .Background (), "ns1" , "sub1" ).Return (nil , nil ).Once ()
1737+ mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (fmt .Errorf ("unique constraint violation" )) // sim another thread winning
1738+ mdi .On ("GetContractListener" , context .Background (), "ns1" , "sub1" ).Return (& core.ContractListener {ID : fftypes .NewUUID (), Name : "sub1" }, nil ).Once ()
1739+
1740+ _ , err := cm .AddContractListener (context .Background (), sub )
1741+ assert .Regexp (t , "FF10312" , err )
1742+
1743+ mbi .AssertExpectations (t )
1744+ mdi .AssertExpectations (t )
1745+ }
1746+
1747+ func TestAddContractListenerBlockchainFailDeleteFail (t * testing.T ) {
1748+ cm := newTestContractManager ()
1749+ mbi := cm .blockchain .(* blockchainmocks.Plugin )
1750+ mdi := cm .database .(* databasemocks.Plugin )
1751+
1752+ sub := & core.ContractListenerInput {
1753+ ContractListener : core.ContractListener {
1754+ Location : fftypes .JSONAnyPtr (fftypes.JSONObject {
1755+ "address" : "0x123" ,
1756+ }.String ()),
1757+ Event : & core.FFISerializedEvent {
1758+ FFIEventDefinition : fftypes.FFIEventDefinition {
1759+ Name : "changed" ,
1760+ Params : fftypes.FFIParams {
1761+ {
1762+ Name : "value" ,
1763+ Schema : fftypes .JSONAnyPtr (`{"type": "integer"}` ),
1764+ },
1765+ },
1766+ },
1767+ },
1768+ Topic : "test-topic" ,
1769+ },
1770+ }
1771+
1772+ mbi .On ("NormalizeContractLocation" , context .Background (), blockchain .NormalizeListener , sub .Location ).Return (sub .Location , nil )
1773+ mbi .On ("GenerateEventSignature" , context .Background (), mock .Anything ).Return ("changed" , nil )
1774+ mbi .On ("GenerateEventSignatureWithLocation" , context .Background (), mock .Anything , mock .Anything ).Return ("0x123:changed" , nil )
1775+ mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
1776+ mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
1777+ mbi .On ("AddContractListener" , context .Background (), & sub .ContractListener , "" ).Return (fmt .Errorf ("pop" )) // backend failure
1778+ mdi .On ("DeleteContractListenerByID" , context .Background (), "ns1" , mock .Anything ).Return (fmt .Errorf ("delete failed" )) // deletion failure
1779+
1780+ _ , err := cm .AddContractListener (context .Background (), sub )
1781+ assert .EqualError (t , err , "pop" )
1782+
1783+ mbi .AssertExpectations (t )
1784+ mdi .AssertExpectations (t )
1785+ }
1786+
1787+ func TestAddContractListenerUnnamedProvisionalBackendID (t * testing.T ) {
1788+ cm := newTestContractManager ()
1789+ mbi := cm .blockchain .(* blockchainmocks.Plugin )
1790+ mdi := cm .database .(* databasemocks.Plugin )
1791+
1792+ sub := & core.ContractListenerInput {
1793+ ContractListener : core.ContractListener {
1794+ Location : fftypes .JSONAnyPtr (fftypes.JSONObject {
1795+ "address" : "0x123" ,
1796+ }.String ()),
1797+ Event : & core.FFISerializedEvent {
1798+ FFIEventDefinition : fftypes.FFIEventDefinition {
1799+ Name : "changed" ,
1800+ Params : fftypes.FFIParams {
1801+ {
1802+ Name : "value" ,
1803+ Schema : fftypes .JSONAnyPtr (`{"type": "integer"}` ),
1804+ },
1805+ },
1806+ },
1807+ },
1808+ Topic : "test-topic" ,
1809+ },
1810+ }
1811+
1812+ mbi .On ("NormalizeContractLocation" , context .Background (), blockchain .NormalizeListener , sub .Location ).Return (sub .Location , nil )
1813+ mbi .On ("GenerateEventSignature" , context .Background (), mock .Anything ).Return ("changed" , nil )
1814+ mbi .On ("GenerateEventSignatureWithLocation" , context .Background (), mock .Anything , mock .Anything ).Return ("0x123:changed" , nil )
1815+ mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
1816+ // The unnamed listener is inserted with its ID as the name, and a unique provisional backend ID
1817+ mdi .On ("InsertContractListener" , context .Background (), mock .MatchedBy (func (l * core.ContractListener ) bool {
1818+ return l .Name == l .ID .String () && l .BackendID == "pending-" + l .ID .String ()
1819+ })).Return (nil )
1820+ // The connector assigns the real backend ID, which is written back to the row
1821+ mbi .On ("AddContractListener" , context .Background (), mock .MatchedBy (func (l * core.ContractListener ) bool {
1822+ l .BackendID = "sb-12345"
1823+ return true
1824+ }), "" ).Return (nil )
1825+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .MatchedBy (func (u ffapi.Update ) bool {
1826+ uu , _ := u .Finalize ()
1827+ return strings .Contains (uu .String (), "sb-12345" )
1828+ })).Return (nil )
1829+
1830+ result , err := cm .AddContractListener (context .Background (), sub )
1831+ assert .NoError (t , err )
1832+ assert .Equal (t , result .ID .String (), result .Name )
1833+ assert .Equal (t , "sb-12345" , result .BackendID )
1834+
1835+ mbi .AssertExpectations (t )
1836+ mdi .AssertExpectations (t )
1837+ }
1838+
1839+ func TestAddContractListenerUpdateBackendIDFail (t * testing.T ) {
1840+ cm := newTestContractManager ()
1841+ mbi := cm .blockchain .(* blockchainmocks.Plugin )
1842+ mdi := cm .database .(* databasemocks.Plugin )
1843+
1844+ sub := & core.ContractListenerInput {
1845+ ContractListener : core.ContractListener {
1846+ Location : fftypes .JSONAnyPtr (fftypes.JSONObject {
1847+ "address" : "0x123" ,
1848+ }.String ()),
1849+ Event : & core.FFISerializedEvent {
1850+ FFIEventDefinition : fftypes.FFIEventDefinition {
1851+ Name : "changed" ,
1852+ Params : fftypes.FFIParams {
1853+ {
1854+ Name : "value" ,
1855+ Schema : fftypes .JSONAnyPtr (`{"type": "integer"}` ),
1856+ },
1857+ },
1858+ },
1859+ },
1860+ Topic : "test-topic" ,
1861+ },
1862+ }
1863+
1864+ mbi .On ("NormalizeContractLocation" , context .Background (), blockchain .NormalizeListener , sub .Location ).Return (sub .Location , nil )
1865+ mbi .On ("GenerateEventSignature" , context .Background (), mock .Anything ).Return ("changed" , nil )
1866+ mbi .On ("GenerateEventSignatureWithLocation" , context .Background (), mock .Anything , mock .Anything ).Return ("0x123:changed" , nil )
1867+ mdi .On ("GetContractListeners" , context .Background (), "ns1" , mock .Anything ).Return (nil , nil , nil )
1868+ mdi .On ("InsertContractListener" , context .Background (), & sub .ContractListener ).Return (nil )
1869+ mbi .On ("AddContractListener" , context .Background (), & sub .ContractListener , "" ).Return (nil )
1870+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .Anything ).Return (fmt .Errorf ("pop" ))
16911871
16921872 _ , err := cm .AddContractListener (context .Background (), sub )
16931873 assert .EqualError (t , err , "pop" )
@@ -1732,6 +1912,7 @@ func TestAddContractAPIListener(t *testing.T) {
17321912 mdi .On ("InsertContractListener" , context .Background (), mock .MatchedBy (func (l * core.ContractListener ) bool {
17331913 return * l .Filters [0 ].Interface .ID == * interfaceID && l .Filters [0 ].Event .Name == "changed" && l .Topic == "test-topic"
17341914 })).Return (nil )
1915+ mdi .On ("UpdateContractListener" , context .Background (), "ns1" , mock .Anything , mock .Anything ).Return (nil )
17351916
17361917 _ , err := cm .AddContractAPIListener (context .Background (), "simple" , "changed" , listener )
17371918 assert .NoError (t , err )
0 commit comments