@@ -658,16 +658,19 @@ class MethodBuilderTest
658658
659659 val stackClient = TestStackClient (stack, params)
660660 val initialMethodBuilder = MethodBuilder .from(" with backups" , stackClient)
661+ assert(initialMethodBuilder.config.backup == None )
662+
661663 val methodBuilder =
662- initialMethodBuilder.withConfig(initialMethodBuilder.config.copy(backup = configuredBrfParam))
664+ initialMethodBuilder.withConfig(
665+ initialMethodBuilder.config.copy(backup = Some (configuredBrfParam)))
663666
664667 // Ensure BRF is configured before calling `nonIdempotent`
665- assert(methodBuilder.config.backup == configuredBrfParam)
668+ assert(methodBuilder.config.backup == Some ( configuredBrfParam) )
666669
667670 val nonIdempotentClient = methodBuilder.nonIdempotent
668671
669672 // Ensure BRF is disabled after calling `nonIdempotent`
670- assert(nonIdempotentClient.config.backup == BackupRequestFilter .Disabled )
673+ assert(nonIdempotentClient.config.backup == Some ( BackupRequestFilter .Disabled ) )
671674 }
672675
673676 test(" nonIdempotent client keeps existing ResponseClassifier in params " ) {
@@ -796,8 +799,9 @@ class MethodBuilderTest
796799 .idempotent(1 .percent, sendInterrupts = true , classifier)
797800
798801 mb.config.backup match {
799- case BackupRequestFilter .Param
800- .Configured (maxExtraLoadTunable, sendInterrupts, minSendBackupAfterMs) =>
802+ case Some (
803+ BackupRequestFilter .Param
804+ .Configured (maxExtraLoadTunable, sendInterrupts, minSendBackupAfterMs)) =>
801805 assert(
802806 maxExtraLoadTunable().get == 1 .percent && sendInterrupts && minSendBackupAfterMs == 1 )
803807 case _ => fail(" BackupRequestFilter not configured" )
@@ -862,8 +866,9 @@ class MethodBuilderTest
862866 .idempotent(tunable, sendInterrupts = true , ResponseClassifier .Default )
863867
864868 assert(
865- mb.config.backup == BackupRequestFilter
866- .Configured (tunable, sendInterrupts = true )
869+ mb.config.backup == Some (
870+ BackupRequestFilter
871+ .Configured (tunable, sendInterrupts = true ))
867872 )
868873 }
869874
@@ -880,12 +885,13 @@ class MethodBuilderTest
880885 .idempotent(tunable, sendInterrupts = true , ResponseClassifier .Default )
881886
882887 assert(
883- mb.config.backup == BackupRequestFilter
884- .Configured (tunable, sendInterrupts = true )
888+ mb.config.backup == Some (
889+ BackupRequestFilter
890+ .Configured (tunable, sendInterrupts = true ))
885891 )
886892
887893 val nonIdempotentMB = mb.nonIdempotent
888- assert(nonIdempotentMB.config.backup == BackupRequestFilter .Disabled )
894+ assert(nonIdempotentMB.config.backup == Some ( BackupRequestFilter .Disabled ) )
889895 }
890896
891897 test(" idempotent combines existing classifier with new one" ) {
@@ -1122,6 +1128,100 @@ class MethodBuilderTest
11221128 assert(client.params[Retries .Budget ].retryBudget eq retryBudget)
11231129 }
11241130
1131+ test(
1132+ " BackupRequestFilter is configured with passed-in stack params when not configured in MethodBuilder" ) {
1133+ val stats = new InMemoryStatsReceiver ()
1134+ val timer = new MockTimer ()
1135+ val params =
1136+ Stack .Params .empty +
1137+ param.Stats (stats) +
1138+ param.Timer (timer) +
1139+ BackupRequestFilter .Configured (maxExtraLoad = 0.01 , sendInterrupts = true )
1140+
1141+ val svc : Service [Int , Int ] = Service .mk { i =>
1142+ Future .value(i)
1143+ }
1144+
1145+ val stack = Stack .leaf(Stack .Role (" test" ), ServiceFactory .const(svc))
1146+
1147+ val stackClient = TestStackClient (stack, Stack .Params .empty).withParams(params)
1148+ val mb = MethodBuilder .from(" mb" , stackClient)
1149+
1150+ Time .withCurrentTimeFrozen { tc =>
1151+ val client = mb.newService(" a_client" )
1152+ awaitResult(client(1 ))
1153+
1154+ tc.advance(10 .seconds)
1155+ timer.tick()
1156+ assert(stats.stats.contains(Seq (" mb" , " a_client" , " backups" , " send_backup_after_ms" )))
1157+ }
1158+ }
1159+
1160+ test(
1161+ " BackupRequestFilter is configured with MethodBuilder idempotent configuration when also configured via stack params" ) {
1162+ val stats = new InMemoryStatsReceiver ()
1163+ val timer = new MockTimer ()
1164+ val params =
1165+ Stack .Params .empty +
1166+ param.Stats (stats) +
1167+ param.Timer (timer) +
1168+ BackupRequestFilter .Disabled
1169+
1170+ val svc : Service [Int , Int ] = Service .mk { i =>
1171+ Future .value(i)
1172+ }
1173+
1174+ val stack = Stack .leaf(Stack .Role (" test" ), ServiceFactory .const(svc))
1175+
1176+ val stackClient = TestStackClient (stack, Stack .Params .empty).withParams(params)
1177+ val classifier : ResponseClassifier = ResponseClassifier .named(" foo" ) {
1178+ case ReqRep (_, Throw (_ : IndividualRequestTimeoutException )) =>
1179+ ResponseClass .RetryableFailure
1180+ }
1181+
1182+ // MB config should take precedence
1183+ val mb = MethodBuilder .from(" mb" , stackClient).idempotent(0.05 , true , classifier)
1184+
1185+ Time .withCurrentTimeFrozen { tc =>
1186+ val client = mb.newService(" a_client" )
1187+ awaitResult(client(1 ))
1188+
1189+ tc.advance(10 .seconds)
1190+ timer.tick()
1191+ assert(stats.stats.contains(Seq (" mb" , " a_client" , " backups" , " send_backup_after_ms" )))
1192+ }
1193+ }
1194+
1195+ test(
1196+ " BackupRequestFilter is configured with MethodBuilder nonIdempotent configuration when also configured via stack params" ) {
1197+ val stats = new InMemoryStatsReceiver ()
1198+ val timer = new MockTimer ()
1199+ val params =
1200+ Stack .Params .empty +
1201+ param.Stats (stats) +
1202+ param.Timer (timer) +
1203+ BackupRequestFilter .Configured (maxExtraLoad = 0.01 , sendInterrupts = true )
1204+
1205+ val svc : Service [Int , Int ] = Service .mk { i =>
1206+ Future .value(i)
1207+ }
1208+
1209+ val stack = Stack .leaf(Stack .Role (" test" ), ServiceFactory .const(svc))
1210+
1211+ val stackClient = TestStackClient (stack, Stack .Params .empty).withParams(params)
1212+ // MB config should take precedence
1213+ val mb = MethodBuilder .from(" mb" , stackClient).nonIdempotent
1214+
1215+ Time .withCurrentTimeFrozen { tc =>
1216+ val client = mb.newService(" a_client" )
1217+ awaitResult(client(1 ))
1218+
1219+ tc.advance(10 .seconds)
1220+ timer.tick()
1221+ assert(! stats.stats.contains(Seq (" mb" , " a_client" , " backups" , " send_backup_after_ms" )))
1222+ }
1223+ }
1224+
11251225 test(" shares RetryBudget between methods" ) {
11261226 val params = StackClient .defaultParams
11271227
0 commit comments