4
4
import org .reactivestreams .Publisher ;
5
5
import org .reactivestreams .Subscriber ;
6
6
import org .reactivestreams .Subscription ;
7
+ import org .reactivestreams .tck .Annotations .Subscribers ;
7
8
import org .reactivestreams .tck .TestEnvironment .ManualPublisher ;
8
9
import org .reactivestreams .tck .TestEnvironment .ManualSubscriber ;
9
10
import org .reactivestreams .tck .TestEnvironment .ManualSubscriberWithSubscriptionSupport ;
10
11
import org .reactivestreams .tck .TestEnvironment .Promise ;
12
+ import org .reactivestreams .tck .support .Function ;
11
13
import org .testng .annotations .BeforeMethod ;
12
14
import org .testng .annotations .Test ;
13
15
@@ -130,17 +132,28 @@ public long maxElementsFromPublisher() {
130
132
}
131
133
132
134
/**
133
- * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
134
- * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
135
- * recursive calls to exceed the number returned by this method.
136
- *
137
- * @see <a href="https://github.com/reactive-streams/reactive-streams#3.3">reactive streams spec, rule 3.3</a>
138
- * @see PublisherVerification#spec303_mustNotAllowUnboundedRecursion()
139
- */
135
+ * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
136
+ * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
137
+ * recursive calls to exceed the number returned by this method.
138
+ *
139
+ * @see <a href="https://github.com/reactive-streams/reactive-streams#3.3">reactive streams spec, rule 3.3</a>
140
+ * @see PublisherVerification#spec303_mustNotAllowUnboundedRecursion()
141
+ */
140
142
public long boundedDepthOfOnNextAndRequestRecursion () {
141
143
return 1 ;
142
144
}
143
145
146
+ /**
147
+ * Describes the tested implementation in terms of how many subscribers they can support.
148
+ * Some tests require the {@code Publisher} under test to support multiple Subscribers,
149
+ * yet the spec does not require all publishers to be able to do so, thus – if an implementation
150
+ * supports only a limited number of subscribers (e.g. only 1 subscriber, also known as "no fanout")
151
+ * you MUST return that number from this method by overriding it.
152
+ */
153
+ public long maxSupportedSubscribers () {
154
+ return Long .MAX_VALUE ;
155
+ }
156
+
144
157
////////////////////// TEST ENV CLEANUP /////////////////////////////////////
145
158
146
159
@ BeforeMethod
@@ -310,31 +323,37 @@ public void spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue()
310
323
311
324
// Verifies rule: https://github.com/reactive-streams/reactive-streams#1.4
312
325
// for multiple subscribers
313
- @ Test
314
- public void spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError () throws Exception {
315
- new TestSetup (env , processorBufferSize ) {{
316
- final ManualSubscriberWithErrorCollection <T > sub1 = new ManualSubscriberWithErrorCollection <T >(env );
317
- env .subscribe (processor , sub1 );
326
+ @ Test @ Subscribers (2 )
327
+ public void spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError () throws Throwable {
328
+ optionalMultipleSubscribersTest (2 , new Function <Long ,TestSetup >() {
329
+ @ Override
330
+ public TestSetup apply (Long aLong ) throws Throwable {
331
+ return new TestSetup (env , processorBufferSize ) {{
332
+ final ManualSubscriberWithErrorCollection <T > sub1 = new ManualSubscriberWithErrorCollection <T >(env );
333
+ env .subscribe (processor , sub1 );
318
334
319
- final ManualSubscriberWithErrorCollection <T > sub2 = new ManualSubscriberWithErrorCollection <T >(env );
320
- env .subscribe (processor , sub2 );
335
+ final ManualSubscriberWithErrorCollection <T > sub2 = new ManualSubscriberWithErrorCollection <T >(env );
336
+ env .subscribe (processor , sub2 );
321
337
322
- sub1 .request (1 );
323
- expectRequest ();
324
- final T x = sendNextTFromUpstream ();
325
- expectNextElement (sub1 , x );
326
- sub1 .request (1 );
338
+ sub1 .request (1 );
339
+ expectRequest ();
340
+ final T x = sendNextTFromUpstream ();
341
+ expectNextElement (sub1 , x );
342
+ sub1 .request (1 );
327
343
328
- // sub1 has received one element, and has one demand pending
329
- // sub2 has not yet requested anything
344
+ // sub1 has received one element, and has one demand pending
345
+ // sub2 has not yet requested anything
330
346
331
- final Exception ex = new RuntimeException ("Test exception" );
332
- sendError (ex );
333
- sub1 .expectError (ex );
334
- sub2 .expectError (ex );
347
+ final Exception ex = new RuntimeException ("Test exception" );
348
+ sendError (ex );
349
+ sub1 .expectError (ex );
350
+ sub2 .expectError (ex );
335
351
336
- env .verifyNoAsyncErrors ();
337
- }};
352
+ env .verifyNoAsyncErrors ();
353
+ }};
354
+
355
+ }
356
+ });
338
357
}
339
358
340
359
////////////////////// SUBSCRIBER RULES VERIFICATION ///////////////////////////
@@ -580,49 +599,54 @@ public void spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Thr
580
599
581
600
// A Processor
582
601
// must trigger `requestFromUpstream` for elements that have been requested 'long ago'
583
- @ Test
584
- public void mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo () throws Exception {
585
- new TestSetup (env , processorBufferSize ) {{
586
- ManualSubscriber <T > sub1 = newSubscriber ();
587
- sub1 .request (20 );
602
+ @ Test @ Subscribers (2 )
603
+ public void mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo () throws Throwable {
604
+ optionalMultipleSubscribersTest (2 , new Function <Long ,TestSetup >() {
605
+ @ Override
606
+ public TestSetup apply (Long subscribers ) throws Throwable {
607
+ return new TestSetup (env , processorBufferSize ) {{
608
+ ManualSubscriber <T > sub1 = newSubscriber ();
609
+ sub1 .request (20 );
588
610
589
- long totalRequests = expectRequest ();
590
- final T x = sendNextTFromUpstream ();
591
- expectNextElement (sub1 , x );
611
+ long totalRequests = expectRequest ();
612
+ final T x = sendNextTFromUpstream ();
613
+ expectNextElement (sub1 , x );
592
614
593
- if (totalRequests == 1 ) {
594
- totalRequests += expectRequest ();
595
- }
596
- final T y = sendNextTFromUpstream ();
597
- expectNextElement (sub1 , y );
615
+ if (totalRequests == 1 ) {
616
+ totalRequests += expectRequest ();
617
+ }
618
+ final T y = sendNextTFromUpstream ();
619
+ expectNextElement (sub1 , y );
598
620
599
- if (totalRequests == 2 ) {
600
- totalRequests += expectRequest ();
601
- }
621
+ if (totalRequests == 2 ) {
622
+ totalRequests += expectRequest ();
623
+ }
602
624
603
- ManualSubscriber <T > sub2 = newSubscriber ();
625
+ final ManualSubscriber <T > sub2 = newSubscriber ();
604
626
605
- // sub1 now has 18 pending
606
- // sub2 has 0 pending
627
+ // sub1 now has 18 pending
628
+ // sub2 has 0 pending
607
629
608
- final T z = sendNextTFromUpstream ();
609
- expectNextElement (sub1 , z );
610
- sub2 .expectNone (); // since sub2 hasn't requested anything yet
630
+ final T z = sendNextTFromUpstream ();
631
+ expectNextElement (sub1 , z );
632
+ sub2 .expectNone (); // since sub2 hasn't requested anything yet
611
633
612
- sub2 .request (1 );
613
- expectNextElement (sub2 , z );
634
+ sub2 .request (1 );
635
+ expectNextElement (sub2 , z );
614
636
615
- if (totalRequests == 3 ) {
616
- expectRequest ();
617
- }
637
+ if (totalRequests == 3 ) {
638
+ expectRequest ();
639
+ }
618
640
619
- // to avoid error messages during test harness shutdown
620
- sendCompletion ();
621
- sub1 .expectCompletion (env .defaultTimeoutMillis ());
622
- sub2 .expectCompletion (env .defaultTimeoutMillis ());
641
+ // to avoid error messages during test harness shutdown
642
+ sendCompletion ();
643
+ sub1 .expectCompletion (env .defaultTimeoutMillis ());
644
+ sub2 .expectCompletion (env .defaultTimeoutMillis ());
623
645
624
- env .verifyNoAsyncErrors ();
625
- }};
646
+ env .verifyNoAsyncErrors ();
647
+ }};
648
+ }
649
+ });
626
650
}
627
651
628
652
/////////////////////// TEST INFRASTRUCTURE //////////////////////
@@ -635,6 +659,16 @@ public void notVerified(String message) {
635
659
publisherVerification .notVerified (message );
636
660
}
637
661
662
+ /**
663
+ * Test for feature that REQUIRES multiple subscribers to be supported by Publisher.
664
+ */
665
+ public void optionalMultipleSubscribersTest (long requiredSubscribersSupport , Function <Long , TestSetup > body ) throws Throwable {
666
+ if (requiredSubscribersSupport > maxSupportedSubscribers ())
667
+ notVerified ("The Publisher under test only supports " +maxSupportedSubscribers ()+ " subscribers, " +
668
+ "while this test requires at least " + requiredSubscribersSupport + "to run." );
669
+ else body .apply (requiredSubscribersSupport );
670
+ }
671
+
638
672
public abstract class TestSetup extends ManualPublisher <T > {
639
673
final private ManualSubscriber <T > tees ; // gives us access to an infinite stream of T values
640
674
private Set <T > seenTees = new HashSet <T >();
0 commit comments