@@ -1667,6 +1667,140 @@ func TestAllCapsPriceInfo(t *testing.T) {
16671667 }
16681668}
16691669
1670+ func TestBYOCExternalCapabilityConstant (t * testing.T ) {
1671+ assert := assert .New (t )
1672+ assert .Equal (Capability (37 ), Capability_BYOC )
1673+
1674+ name , ok := CapabilityNameLookup [Capability_BYOC ]
1675+ assert .True (ok , "Capability_BYOC should exist in CapabilityNameLookup" )
1676+ assert .Equal ("byoc" , name )
1677+ }
1678+
1679+ func TestBYOCExternalCapsPriceInfo (t * testing.T ) {
1680+ n , _ := NewLivepeerNode (nil , "" , nil )
1681+ n .SetBasePrice ("default" , NewFixedPrice (big .NewRat (1 , 1 )))
1682+ n .Recipient = new (pm.MockRecipient )
1683+ orch := NewOrchestrator (n , nil )
1684+
1685+ addr1 := "0x1000000000000000000000000000000000000000"
1686+
1687+ n .ExternalCapabilities .Capabilities ["my-service" ] = & ExternalCapability {Name : "my-service" }
1688+ n .ExternalCapabilities .Capabilities ["another-service" ] = & ExternalCapability {Name : "another-service" }
1689+ n .SetPriceForExternalCapability ("default" , "my-service" , big .NewRat (10 , 1 ))
1690+ n .SetPriceForExternalCapability ("default" , "another-service" , big .NewRat (20 , 1 ))
1691+
1692+ // Also set a built-in cap price so we verify both coexist
1693+ n .SetBasePriceForCap ("default" , Capability_TextToImage , "default" , NewFixedPrice (big .NewRat (5 , 1 )))
1694+
1695+ prices , err := orch .GetCapabilitiesPrices (ethcommon .HexToAddress (addr1 ))
1696+ assert .Nil (t , err )
1697+ assert .Len (t , prices , 3 ) // 1 built-in + 2 BYOC external
1698+
1699+ byocPrices := map [string ]* net.PriceInfo {}
1700+ builtInCount := 0
1701+ for _ , p := range prices {
1702+ if p .Capability == uint32 (Capability_BYOC ) {
1703+ byocPrices [p .Constraint ] = p
1704+ } else {
1705+ builtInCount ++
1706+ }
1707+ }
1708+ assert .Equal (t , 1 , builtInCount )
1709+ assert .Len (t , byocPrices , 2 )
1710+
1711+ myService := byocPrices ["my-service" ]
1712+ assert .NotNil (t , myService )
1713+ assert .Equal (t , int64 (10 ), myService .PricePerUnit )
1714+ assert .Equal (t , int64 (1 ), myService .PixelsPerUnit )
1715+ assert .Equal (t , uint32 (Capability_BYOC ), myService .Capability )
1716+ assert .Equal (t , "my-service" , myService .Constraint )
1717+
1718+ anotherService := byocPrices ["another-service" ]
1719+ assert .NotNil (t , anotherService )
1720+ assert .Equal (t , int64 (20 ), anotherService .PricePerUnit )
1721+ }
1722+
1723+ func TestBYOCExternalCapsSenderPricing (t * testing.T ) {
1724+ n , _ := NewLivepeerNode (nil , "" , nil )
1725+ n .SetBasePrice ("default" , NewFixedPrice (big .NewRat (1 , 1 )))
1726+ n .Recipient = new (pm.MockRecipient )
1727+ orch := NewOrchestrator (n , nil )
1728+
1729+ addr1 := "0x1000000000000000000000000000000000000000"
1730+ addr2 := "0x2000000000000000000000000000000000000000"
1731+ addr3 := "0x3000000000000000000000000000000000000000"
1732+
1733+ n .ExternalCapabilities .Capabilities ["my-service" ] = & ExternalCapability {Name : "my-service" }
1734+ n .SetPriceForExternalCapability ("default" , "my-service" , big .NewRat (10 , 1 ))
1735+ n .SetPriceForExternalCapability (addr1 , "my-service" , big .NewRat (100 , 1 ))
1736+ n .SetPriceForExternalCapability (addr2 , "my-service" , big .NewRat (200 , 1 ))
1737+
1738+ getBYOCPrice := func (addr string ) int64 {
1739+ prices , err := orch .GetCapabilitiesPrices (ethcommon .HexToAddress (addr ))
1740+ assert .Nil (t , err )
1741+ for _ , p := range prices {
1742+ if p .Capability == uint32 (Capability_BYOC ) {
1743+ return p .PricePerUnit
1744+ }
1745+ }
1746+ t .Fatalf ("no BYOC price found for %s" , addr )
1747+ return 0
1748+ }
1749+
1750+ assert .Equal (t , int64 (100 ), getBYOCPrice (addr1 ), "sender-specific price" )
1751+ assert .Equal (t , int64 (200 ), getBYOCPrice (addr2 ), "sender-specific price" )
1752+ assert .Equal (t , int64 (10 ), getBYOCPrice (addr3 ), "falls back to default" )
1753+ }
1754+
1755+ func TestBYOCExternalCapsPriceEdgeCases (t * testing.T ) {
1756+ addr := "0x1000000000000000000000000000000000000000"
1757+
1758+ tests := []struct {
1759+ name string
1760+ price * big.Rat
1761+ nilExtCaps bool
1762+ expectPresent bool
1763+ expectPrice int64
1764+ }{
1765+ {"zero price included" , big .NewRat (0 , 1 ), false , true , 0 },
1766+ {"negative price skipped" , big .NewRat (- 5 , 1 ), false , false , 0 },
1767+ {"nil ExternalCapabilities" , nil , true , false , 0 },
1768+ }
1769+
1770+ for _ , tt := range tests {
1771+ t .Run (tt .name , func (t * testing.T ) {
1772+ n , _ := NewLivepeerNode (nil , "" , nil )
1773+ n .SetBasePrice ("default" , NewFixedPrice (big .NewRat (1 , 1 )))
1774+ n .Recipient = new (pm.MockRecipient )
1775+
1776+ if tt .nilExtCaps {
1777+ n .ExternalCapabilities = nil
1778+ } else {
1779+ n .ExternalCapabilities .Capabilities ["svc" ] = & ExternalCapability {Name : "svc" }
1780+ n .SetPriceForExternalCapability ("default" , "svc" , tt .price )
1781+ }
1782+
1783+ orch := NewOrchestrator (n , nil )
1784+ prices , err := orch .GetCapabilitiesPrices (ethcommon .HexToAddress (addr ))
1785+ assert .Nil (t , err )
1786+
1787+ var byocPrice * net.PriceInfo
1788+ for _ , p := range prices {
1789+ if p .Capability == uint32 (Capability_BYOC ) {
1790+ byocPrice = p
1791+ }
1792+ }
1793+
1794+ if tt .expectPresent {
1795+ assert .NotNil (t , byocPrice , "BYOC price should be present" )
1796+ assert .Equal (t , tt .expectPrice , byocPrice .PricePerUnit )
1797+ } else {
1798+ assert .Nil (t , byocPrice , "BYOC price should not be present" )
1799+ }
1800+ })
1801+ }
1802+ }
1803+
16701804func TestDebitFees (t * testing.T ) {
16711805 n , _ := NewLivepeerNode (nil , "" , nil )
16721806 n .Balances = NewAddressBalances (5 * time .Second )
0 commit comments