@@ -2007,4 +2007,119 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils {
20072007
20082008    // Required to receive ETH when withdrawing funds 
20092009    receive () external  payable  {}
2010+ 
2011+     function testUpdateSubscriptionRemovesPriceUpdatesForRemovedPriceIds  () public  {
2012+         // 1. Setup: Add subscription with 3 price feeds, update prices 
2013+         uint8  numInitialFeeds =  3 ;
2014+         uint256  subscriptionId =  addTestSubscriptionWithFeeds (
2015+             scheduler,
2016+             numInitialFeeds,
2017+             address (reader)
2018+         );
2019+         scheduler.addFunds {value: 1  ether }(subscriptionId);
2020+ 
2021+         // Get initial price IDs and create mock price feeds 
2022+         bytes32 [] memory  initialPriceIds =  createPriceIds (numInitialFeeds);
2023+         uint64  publishTime =  SafeCast.toUint64 (block .timestamp );
2024+         
2025+         // Setup and perform initial price update 
2026+         (PythStructs.PriceFeed[] memory  priceFeeds , uint64 [] memory  slots ) =  
2027+             createMockPriceFeedsWithSlots (publishTime, numInitialFeeds);
2028+         mockParsePriceFeedUpdatesWithSlots (pyth, priceFeeds, slots);
2029+         
2030+         vm.prank (pusher);
2031+         scheduler.updatePriceFeeds (subscriptionId, createMockUpdateData (priceFeeds));
2032+ 
2033+         // Store the removed price ID for later use 
2034+         bytes32  removedPriceId =  initialPriceIds[numInitialFeeds -  1 ];
2035+ 
2036+         // 2. Action: Update subscription to remove the last price feed 
2037+         (SchedulerState.SubscriptionParams memory  params , ) =  scheduler.getSubscription (subscriptionId);
2038+         
2039+         // Create new price IDs array without the last ID 
2040+         bytes32 [] memory  newPriceIds =  new  bytes32 [](numInitialFeeds -  1 );
2041+         for  (uint  i =  0 ; i <  newPriceIds.length ; i++ ) {
2042+             newPriceIds[i] =  initialPriceIds[i];
2043+         }
2044+         
2045+         params.priceIds =  newPriceIds;
2046+         
2047+         vm.expectEmit ();
2048+         emit  SubscriptionUpdated (subscriptionId);
2049+         scheduler.updateSubscription (subscriptionId, params);
2050+ 
2051+         // 3. Verification: 
2052+         // - Verify that the removed price ID is no longer part of the subscription's price IDs 
2053+         (SchedulerState.SubscriptionParams memory  updatedParams , ) =  scheduler.getSubscription (subscriptionId);
2054+         assertEq (
2055+             updatedParams.priceIds.length ,
2056+             numInitialFeeds -  1 ,
2057+             "Subscription should have one less price ID " 
2058+         );
2059+         
2060+         bool  removedPriceIdFound =  false ;
2061+         for  (uint  i =  0 ; i <  updatedParams.priceIds.length ; i++ ) {
2062+             if  (updatedParams.priceIds[i] ==  removedPriceId) {
2063+                 removedPriceIdFound =  true ;
2064+                 break ;
2065+             }
2066+         }
2067+         assertFalse (
2068+             removedPriceIdFound,
2069+             "Removed price ID should not be in the subscription's price IDs " 
2070+         );
2071+ 
2072+         // - Querying all feeds should return only the remaining feeds 
2073+         PythStructs.Price[] memory  allPricesAfterUpdate =  scheduler
2074+             .getPricesUnsafe (subscriptionId, new  bytes32 [](0 ));
2075+         assertEq (
2076+             allPricesAfterUpdate.length ,
2077+             newPriceIds.length ,
2078+             "Querying all should only return remaining feeds " 
2079+         );
2080+         
2081+         // - Verify that the removed price ID is not included in the returned prices 
2082+         for  (uint  i =  0 ; i <  allPricesAfterUpdate.length ; i++ ) {
2083+             // We can't directly check the price ID from the Price struct 
2084+             // But we can verify that the number of returned prices matches the number of price IDs 
2085+             // in the updated subscription, which indirectly confirms that removed price IDs are not included 
2086+             assertEq (
2087+                 allPricesAfterUpdate.length ,
2088+                 updatedParams.priceIds.length ,
2089+                 "Number of returned prices should match number of price IDs in subscription " 
2090+             );
2091+         }
2092+     }
2093+     
2094+ 
2095+ 
2096+     function testUpdateSubscriptionRevertsWithTooManyPriceIds  () public  {
2097+         // 1. Setup: Create a subscription with a valid number of price IDs 
2098+         uint8  initialNumFeeds =  2 ;
2099+         uint256  subscriptionId =  addTestSubscriptionWithFeeds (
2100+             scheduler,
2101+             initialNumFeeds,
2102+             address (reader)
2103+         );
2104+ 
2105+         // 2. Prepare params with too many price IDs (MAX_PRICE_IDS_PER_SUBSCRIPTION + 1) 
2106+         (SchedulerState.SubscriptionParams memory  currentParams , ) =  scheduler
2107+             .getSubscription (subscriptionId);
2108+         
2109+         uint16  tooManyFeeds =  uint16 (scheduler.MAX_PRICE_IDS_PER_SUBSCRIPTION ()) +  1 ;
2110+         bytes32 [] memory  tooManyPriceIds =  createPriceIds (tooManyFeeds);
2111+         
2112+         SchedulerState.SubscriptionParams memory  newParams =  currentParams;
2113+         newParams.priceIds =  tooManyPriceIds;
2114+ 
2115+         // 3. Expect revert when trying to update with too many price IDs 
2116+         vm.expectRevert (
2117+             abi.encodeWithSelector (
2118+                 TooManyPriceIds.selector ,
2119+                 tooManyFeeds,
2120+                 scheduler.MAX_PRICE_IDS_PER_SUBSCRIPTION ()
2121+             )
2122+         );
2123+         scheduler.updateSubscription (subscriptionId, newParams);
2124+     }
20102125}
0 commit comments