From 8b8bb9e0e391803c2602ec6024001662734aaba8 Mon Sep 17 00:00:00 2001 From: Roland Kuhn Date: Fri, 1 May 2015 11:39:08 +0200 Subject: [PATCH 1/2] update to 1.0.0 artifacts --- _includes/index.md | 24 +- .../allclasses-frame.html | 22 + .../allclasses-noframe.html | 22 + .../constant-values.html | 120 ++ .../deprecated-list.html | 120 ++ reactive-streams-1.0.0-javadoc/help-doc.html | 217 ++ reactive-streams-1.0.0-javadoc/index-all.html | 195 ++ reactive-streams-1.0.0-javadoc/index.html | 72 + .../org/reactivestreams/Processor.html | 203 ++ .../org/reactivestreams/Publisher.html | 246 +++ .../org/reactivestreams/Subscriber.html | 311 +++ .../org/reactivestreams/Subscription.html | 255 +++ .../org/reactivestreams/package-frame.html | 23 + .../org/reactivestreams/package-summary.html | 160 ++ .../org/reactivestreams/package-tree.html | 135 ++ .../overview-tree.html | 139 ++ reactive-streams-1.0.0-javadoc/package-list | 1 + reactive-streams-1.0.0-javadoc/script.js | 30 + .../org/reactivestreams/Processor.html | 83 + .../org/reactivestreams/Publisher.html | 101 + .../org/reactivestreams/Subscriber.html | 127 ++ .../org/reactivestreams/Subscription.html | 105 + reactive-streams-1.0.0-javadoc/stylesheet.css | 574 +++++ .../allclasses-frame.html | 23 + .../allclasses-noframe.html | 23 + .../constant-values.html | 120 ++ .../deprecated-list.html | 120 ++ .../help-doc.html | 217 ++ .../index-all.html | 229 ++ .../index.html | 72 + .../unicast/AsyncIterablePublisher.html | 303 +++ .../example/unicast/AsyncSubscriber.html | 394 ++++ .../InfiniteIncrementNumberPublisher.html | 249 +++ .../unicast/NumberIterablePublisher.html | 253 +++ .../example/unicast/SyncSubscriber.html | 349 +++ .../example/unicast/package-frame.html | 24 + .../example/unicast/package-summary.html | 166 ++ .../example/unicast/package-tree.html | 136 ++ .../overview-tree.html | 140 ++ .../package-list | 1 + .../script.js | 30 + .../unicast/AsyncIterablePublisher.html | 330 +++ .../example/unicast/AsyncSubscriber.html | 310 +++ .../InfiniteIncrementNumberPublisher.html | 95 + .../unicast/NumberIterablePublisher.html | 99 + .../example/unicast/SyncSubscriber.html | 183 ++ .../stylesheet.css | 574 +++++ .../allclasses-frame.html | 50 + .../allclasses-noframe.html | 50 + .../constant-values.html | 177 ++ .../deprecated-list.html | 122 ++ .../help-doc.html | 223 ++ .../index-all.html | 1506 +++++++++++++ reactive-streams-tck-1.0.0-javadoc/index.html | 75 + ...n.ManualSubscriberWithErrorCollection.html | 372 ++++ ...entityProcessorVerification.TestSetup.html | 374 ++++ .../tck/IdentityProcessorVerification.html | 1888 +++++++++++++++++ ...ublisherVerification.PublisherTestRun.html | 228 ++ .../tck/PublisherVerification.html | 1426 +++++++++++++ ...lackboxVerification.BlackboxTestStage.html | 462 ++++ .../tck/SubscriberBlackboxVerification.html | 992 +++++++++ ...berWhiteboxVerification.BlackboxProbe.html | 672 ++++++ ...xVerification.BlackboxSubscriberProxy.html | 367 ++++ ...rWhiteboxVerification.SubscriberProbe.html | 264 +++ ...WhiteboxVerification.SubscriberPuppet.html | 236 +++ ...teboxVerification.SubscriberPuppeteer.html | 232 ++ ...xVerification.WhiteboxSubscriberProbe.html | 345 +++ ...hiteboxVerification.WhiteboxTestStage.html | 496 +++++ .../tck/SubscriberWhiteboxVerification.html | 1050 +++++++++ ...holeSubscriberWithSubscriptionSupport.html | 385 ++++ .../tck/TestEnvironment.Latch.html | 364 ++++ .../tck/TestEnvironment.ManualPublisher.html | 561 +++++ .../tck/TestEnvironment.ManualSubscriber.html | 1135 ++++++++++ ...nualSubscriberWithSubscriptionSupport.html | 385 ++++ .../tck/TestEnvironment.Promise.html | 359 ++++ .../tck/TestEnvironment.Receptacle.html | 380 ++++ .../tck/TestEnvironment.TestSubscriber.html | 388 ++++ .../reactivestreams/tck/TestEnvironment.html | 790 +++++++ .../tck/WithHelperPublisher.html | 344 +++ .../reactivestreams/tck/package-frame.html | 43 + .../reactivestreams/tck/package-summary.html | 251 +++ .../org/reactivestreams/tck/package-tree.html | 180 ++ .../reactivestreams/tck/support/Function.html | 226 ++ .../tck/support/HelperPublisher.html | 257 +++ .../tck/support/InfiniteHelperPublisher.html | 253 +++ .../reactivestreams/tck/support/NonFatal.html | 245 +++ .../tck/support/Optional.Some.html | 304 +++ .../reactivestreams/tck/support/Optional.html | 329 +++ .../support/PublisherVerificationRules.html | 860 ++++++++ .../SubscriberBlackboxVerificationRules.html | 662 ++++++ .../SubscriberBufferOverflowException.html | 303 +++ .../SubscriberWhiteboxVerificationRules.html | 698 ++++++ .../tck/support/TestException.html | 267 +++ .../tck/support/package-frame.html | 36 + .../tck/support/package-summary.html | 212 ++ .../tck/support/package-tree.html | 167 ++ .../overview-frame.html | 22 + .../overview-summary.html | 140 ++ .../overview-tree.html | 211 ++ .../package-list | 2 + reactive-streams-tck-1.0.0-javadoc/script.js | 30 + .../serialized-form.html | 140 ++ ...n.ManualSubscriberWithErrorCollection.html | 834 ++++++++ ...entityProcessorVerification.TestSetup.html | 834 ++++++++ .../tck/IdentityProcessorVerification.html | 834 ++++++++ ...ublisherVerification.PublisherTestRun.html | 1255 +++++++++++ .../tck/PublisherVerification.html | 1255 +++++++++++ ...lackboxVerification.BlackboxTestStage.html | 596 ++++++ .../tck/SubscriberBlackboxVerification.html | 596 ++++++ ...berWhiteboxVerification.BlackboxProbe.html | 857 ++++++++ ...xVerification.BlackboxSubscriberProxy.html | 857 ++++++++ ...rWhiteboxVerification.SubscriberProbe.html | 857 ++++++++ ...WhiteboxVerification.SubscriberPuppet.html | 857 ++++++++ ...teboxVerification.SubscriberPuppeteer.html | 857 ++++++++ ...xVerification.WhiteboxSubscriberProbe.html | 857 ++++++++ ...hiteboxVerification.WhiteboxTestStage.html | 857 ++++++++ .../tck/SubscriberWhiteboxVerification.html | 857 ++++++++ ...holeSubscriberWithSubscriptionSupport.html | 1031 +++++++++ .../tck/TestEnvironment.Latch.html | 1031 +++++++++ .../tck/TestEnvironment.ManualPublisher.html | 1031 +++++++++ .../tck/TestEnvironment.ManualSubscriber.html | 1031 +++++++++ ...nualSubscriberWithSubscriptionSupport.html | 1031 +++++++++ .../tck/TestEnvironment.Promise.html | 1031 +++++++++ .../tck/TestEnvironment.Receptacle.html | 1031 +++++++++ .../tck/TestEnvironment.TestSubscriber.html | 1031 +++++++++ .../reactivestreams/tck/TestEnvironment.html | 1031 +++++++++ .../tck/WithHelperPublisher.html | 141 ++ .../reactivestreams/tck/support/Function.html | 77 + .../tck/support/HelperPublisher.html | 105 + .../tck/support/InfiniteHelperPublisher.html | 102 + .../reactivestreams/tck/support/NonFatal.html | 104 + .../tck/support/Optional.Some.html | 141 ++ .../reactivestreams/tck/support/Optional.html | 141 ++ .../support/PublisherVerificationRules.html | 117 + .../SubscriberBlackboxVerificationRules.html | 105 + .../SubscriberBufferOverflowException.html | 90 + .../SubscriberWhiteboxVerificationRules.html | 107 + .../tck/support/TestException.html | 83 + .../stylesheet.css | 574 +++++ 139 files changed, 54475 insertions(+), 12 deletions(-) create mode 100644 reactive-streams-1.0.0-javadoc/allclasses-frame.html create mode 100644 reactive-streams-1.0.0-javadoc/allclasses-noframe.html create mode 100644 reactive-streams-1.0.0-javadoc/constant-values.html create mode 100644 reactive-streams-1.0.0-javadoc/deprecated-list.html create mode 100644 reactive-streams-1.0.0-javadoc/help-doc.html create mode 100644 reactive-streams-1.0.0-javadoc/index-all.html create mode 100644 reactive-streams-1.0.0-javadoc/index.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/Processor.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/Publisher.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscription.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/package-frame.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/package-summary.html create mode 100644 reactive-streams-1.0.0-javadoc/org/reactivestreams/package-tree.html create mode 100644 reactive-streams-1.0.0-javadoc/overview-tree.html create mode 100644 reactive-streams-1.0.0-javadoc/package-list create mode 100644 reactive-streams-1.0.0-javadoc/script.js create mode 100644 reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Processor.html create mode 100644 reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Publisher.html create mode 100644 reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscriber.html create mode 100644 reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscription.html create mode 100644 reactive-streams-1.0.0-javadoc/stylesheet.css create mode 100644 reactive-streams-examples-1.0.0-javadoc/allclasses-frame.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/allclasses-noframe.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/constant-values.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/deprecated-list.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/help-doc.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/index-all.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/index.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncIterablePublisher.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncSubscriber.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/NumberIterablePublisher.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/SyncSubscriber.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-frame.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-summary.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-tree.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/overview-tree.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/package-list create mode 100644 reactive-streams-examples-1.0.0-javadoc/script.js create mode 100644 reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncIterablePublisher.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncSubscriber.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/NumberIterablePublisher.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/SyncSubscriber.html create mode 100644 reactive-streams-examples-1.0.0-javadoc/stylesheet.css create mode 100644 reactive-streams-tck-1.0.0-javadoc/allclasses-frame.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/allclasses-noframe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/constant-values.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/deprecated-list.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/help-doc.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/index-all.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/index.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Latch.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Promise.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Receptacle.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/WithHelperPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-frame.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-summary.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-tree.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Function.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/HelperPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/InfiniteHelperPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/NonFatal.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.Some.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/PublisherVerificationRules.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/TestException.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-frame.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-summary.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-tree.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/overview-frame.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/overview-summary.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/overview-tree.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/package-list create mode 100644 reactive-streams-tck-1.0.0-javadoc/script.js create mode 100644 reactive-streams-tck-1.0.0-javadoc/serialized-form.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Latch.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Promise.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Receptacle.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/WithHelperPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Function.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/HelperPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/InfiniteHelperPublisher.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/NonFatal.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.Some.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/PublisherVerificationRules.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/TestException.html create mode 100644 reactive-streams-tck-1.0.0-javadoc/stylesheet.css diff --git a/_includes/index.md b/_includes/index.md index 5940ba9..8b7676f 100644 --- a/_includes/index.md +++ b/_includes/index.md @@ -44,20 +44,20 @@ This work is performed in the [reactive-streams-io](https://github.com/reactive- ## Current State -As of Apr 10, 2015 we have released version 1.0.0-RC5 of Reactive Streams for the JVM, including Java [API](http://www.reactive-streams.org/reactive-streams-1.0.0.RC5-javadoc), a textual [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0.RC5/README.md#specification) and a [TCK](http://www.reactive-streams.org/reactive-streams-tck-1.0.0.RC5-javadoc). Corresponding code artifacts are available on Maven Central: +As of April 30, 2015 we have released version 1.0.0 of Reactive Streams for the JVM, including Java [API](/reactive-streams-1.0.0-javadoc), a textual [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification), a [TCK](/reactive-streams-tck-1.0.0-javadoc) and [implementation examples](/reactive-streams-examples-1.0.0-javadoc). Corresponding code artifacts are available on Maven Central: org.reactivestreams reactive-streams - 1.0.0.RC5 + 1.0.0 org.reactivestreams reactive-streams-tck - 1.0.0.RC5 + 1.0.0 -The source code for these is available on [github](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0.RC5). Please use github issues for providing feedback. +The source code for these is available on [github](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0). Please use github issues for providing feedback. All artifacts and specifications are released under [Creative Commons Zero](http://creativecommons.org/publicdomain/zero/1.0) into the Public Domain. @@ -65,26 +65,26 @@ All artifacts and specifications are released under [Creative Commons Zero](http #### On the JVM -* [Akka](http://akka.io/) Streams *(tested with TCK 1.0.0.RC5)* +* [Akka](http://akka.io/) Streams *(tested with TCK 1.0.0)* * See this [Activator template](http://www.typesafe.com/activator/template/akka-stream-scala) and the [documentation](http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-M5/index.html). * Please give [Feedback](http://doc.akka.io/docs/akka/current/project/issue-tracking.html) on the issue tracker. -* [MongoDB](http://mongodb.org) *(tested with TCK 1.0.0.RC5)* +* [MongoDB](http://mongodb.org) *(tested with TCK 1.0.0)* * For the documentation see [here](http://mongodb.github.io/mongo-java-driver-reactivestreams). -* [Ratpack](http://www.ratpack.io) *(tested with TCK 1.0.0.RC5)* +* [Ratpack](http://www.ratpack.io) *(tested with TCK 1.0.0)* * See the [“Streams”](http://www.ratpack.io/manual/current/streams.html) chapter of the manual. * Reactive Rabbit *(tested with TCK 1.0.0.RC3)* * Driver for RabbitMQ/AMQP. * See [github.com/ScalaConsultants/reactive-rabbit](https://github.com/ScalaConsultants/reactive-rabbit). -* [Reactor](http://projectreactor.io/) *(tested with TCK 1.0.0.RC5)* +* [Reactor](http://projectreactor.io/) *(tested with TCK 1.0.0)* * For the documentation see [here](http://projectreactor.io/docs/reference/streams.html). -* [RxJava](http://reactivex.io/) *(tested with TCK 1.0.0.RC5)* +* [RxJava](http://reactivex.io/) *(tested with TCK 1.0.0)* * See [github.com/ReactiveX/RxJavaReactiveStreams](https://github.com/ReactiveX/RxJavaReactiveStreams). -* [Slick](http://slick.typesafe.com/) *(tested with TCK 1.0.0.RC5)* +* [Slick](http://slick.typesafe.com/) *(tested with TCK 1.0.0)* * Provides a *Publisher* for streaming database query results. * See the ["Streaming"](http://slick.typesafe.com/doc/3.0.0-RC3/dbio.html#streaming) section of the manual. -* [Vert.x 3.0](http://vertx.io) *(tested with TCK 1.0.0.RC5)* +* [Vert.x 3.0](http://vertx.io) *(tested with TCK 1.0.0)* * Vert.x 3.0 is currently in alpha. The reactive streams implementation can be found [here](https://github.com/vert-x3/vertx-reactive-streams). ##### A Note for Implementors -To get started implementing the draft specification, it is recommended to start by reading the [README](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0.RC5/README.md) and the [Java API documentation](http://www.reactive-streams.org/reactive-streams-1.0.0.RC5-javadoc), then taking a look at the [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0.RC5/README.md#specification) then taking a look at the [TCK](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0.RC5/tck). If you have an issue with any of the above, please take a look at [closed issues](https://github.com/reactive-streams/reactive-streams-jvm/issues?page=1&state=closed) and then open a [new issue](https://github.com/reactive-streams/reactive-streams-jvm/issues/new) if it has not already been answered. +To get started implementing the draft specification, it is recommended to start by reading the [README](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md) and the [Java API documentation](/reactive-streams-1.0.0-javadoc), then taking a look at the [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification) then taking a look at the [TCK](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0/tck) and the [example implementations](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0/examples/src/main/java/org/reactivestreams/example/unicast). If you have an issue with any of the above, please take a look at [closed issues](https://github.com/reactive-streams/reactive-streams-jvm/issues?page=1&state=closed) and then open a [new issue](https://github.com/reactive-streams/reactive-streams-jvm/issues/new) if it has not already been answered. diff --git a/reactive-streams-1.0.0-javadoc/allclasses-frame.html b/reactive-streams-1.0.0-javadoc/allclasses-frame.html new file mode 100644 index 0000000..24300fb --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/allclasses-frame.html @@ -0,0 +1,22 @@ + + + + + + +All Classes (reactive-streams 1.0.0 API) + + + + +

All Classes

+
+ +
+ + diff --git a/reactive-streams-1.0.0-javadoc/allclasses-noframe.html b/reactive-streams-1.0.0-javadoc/allclasses-noframe.html new file mode 100644 index 0000000..13fe3e8 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/allclasses-noframe.html @@ -0,0 +1,22 @@ + + + + + + +All Classes (reactive-streams 1.0.0 API) + + + + +

All Classes

+
+ +
+ + diff --git a/reactive-streams-1.0.0-javadoc/constant-values.html b/reactive-streams-1.0.0-javadoc/constant-values.html new file mode 100644 index 0000000..6db0a4b --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/constant-values.html @@ -0,0 +1,120 @@ + + + + + + +Constant Field Values (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Constant Field Values

+

Contents

+
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/deprecated-list.html b/reactive-streams-1.0.0-javadoc/deprecated-list.html new file mode 100644 index 0000000..0893944 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/deprecated-list.html @@ -0,0 +1,120 @@ + + + + + + +Deprecated List (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Deprecated API

+

Contents

+
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/help-doc.html b/reactive-streams-1.0.0-javadoc/help-doc.html new file mode 100644 index 0000000..baf4446 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/help-doc.html @@ -0,0 +1,217 @@ + + + + + + +API Help (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

How This API Document Is Organized

+
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
+
+
+ +This help file applies to API documentation generated using the standard doclet.
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/index-all.html b/reactive-streams-1.0.0-javadoc/index-all.html new file mode 100644 index 0000000..82a208b --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/index-all.html @@ -0,0 +1,195 @@ + + + + + + +Index (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
C O P R S  + + +

C

+
+
cancel() - Method in interface org.reactivestreams.Subscription
+
+
Request the Publisher to stop sending data and clean up resources.
+
+
+ + + +

O

+
+
onComplete() - Method in interface org.reactivestreams.Subscriber
+
+
Successful terminal state.
+
+
onError(Throwable) - Method in interface org.reactivestreams.Subscriber
+
+
Failed terminal state.
+
+
onNext(T) - Method in interface org.reactivestreams.Subscriber
+
+
Data notification sent by the Publisher in response to requests to request(long).
+
+
onSubscribe(Subscription) - Method in interface org.reactivestreams.Subscriber
+
+
Invoked after calling Publisher.subscribe(Subscriber).
+
+
org.reactivestreams - package org.reactivestreams
+
 
+
+ + + +

P

+
+
Processor<T,R> - Interface in org.reactivestreams
+
+
A Processor represents a processing stage—which is both a Subscriber + and a Publisher and obeys the contracts of both.
+
+
Publisher<T> - Interface in org.reactivestreams
+
+
A Publisher is a provider of a potentially unbounded number of sequenced elements, publishing them according to + the demand received from its Subscriber(s).
+
+
+ + + +

R

+
+
request(long) - Method in interface org.reactivestreams.Subscription
+
+
No events will be sent by a Publisher until demand is signaled via this method.
+
+
+ + + +

S

+
+
subscribe(Subscriber<? super T>) - Method in interface org.reactivestreams.Publisher
+
+
Request Publisher to start streaming data.
+
+
Subscriber<T> - Interface in org.reactivestreams
+
+
Will receive call to Subscriber.onSubscribe(Subscription) once after passing an instance of Subscriber to Publisher.subscribe(Subscriber).
+
+
Subscription - Interface in org.reactivestreams
+
+
A Subscription represents a one-to-one lifecycle of a Subscriber subscribing to a Publisher.
+
+
+C O P R S 
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/index.html b/reactive-streams-1.0.0-javadoc/index.html new file mode 100644 index 0000000..c81cd25 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/index.html @@ -0,0 +1,72 @@ + + + + + + +reactive-streams 1.0.0 API + + + + + + +<noscript> +<div>JavaScript is disabled on your browser.</div> +</noscript> +<h2>Frame Alert</h2> +<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="org/reactivestreams/package-summary.html">Non-frame version</a>.</p> + + + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/Processor.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Processor.html new file mode 100644 index 0000000..96939ab --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Processor.html @@ -0,0 +1,203 @@ + + + + + + +Processor (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams
+

Interface Processor<T,R>

+
+
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/Publisher.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Publisher.html new file mode 100644 index 0000000..03f0473 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Publisher.html @@ -0,0 +1,246 @@ + + + + + + +Publisher (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams
+

Interface Publisher<T>

+
+
+
+
    +
  • +
    +
    Type Parameters:
    +
    T - the type of element signaled.
    +
    +
    +
    All Known Subinterfaces:
    +
    Processor<T,R>
    +
    +
    +
    +
    public interface Publisher<T>
    +
    A Publisher is a provider of a potentially unbounded number of sequenced elements, publishing them according to + the demand received from its Subscriber(s). +

    + A Publisher can serve multiple Subscribers subscribed subscribe(Subscriber) dynamically + at various points in time.

    +
  • +
+
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html new file mode 100644 index 0000000..6a80a2b --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscriber.html @@ -0,0 +1,311 @@ + + + + + + +Subscriber (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams
+

Interface Subscriber<T>

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscription.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscription.html new file mode 100644 index 0000000..766ae1b --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/Subscription.html @@ -0,0 +1,255 @@ + + + + + + +Subscription (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams
+

Interface Subscription

+
+
+
+
    +
  • +
    +
    +
    public interface Subscription
    +
    A Subscription represents a one-to-one lifecycle of a Subscriber subscribing to a Publisher. +

    + It can only be used once by a single Subscriber. +

    + It is used to both signal desire for data and cancel demand (and allow resource cleanup).

    +
  • +
+
+
+
    +
  • + + +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        request

        +
        void request(long n)
        +
        No events will be sent by a Publisher until demand is signaled via this method. +

        + It can be called however often and whenever needed—but the outstanding cumulative demand must never exceed Long.MAX_VALUE. + An outstanding cumulative demand of Long.MAX_VALUE may be treated by the Publisher as "effectively unbounded". +

        + Whatever has been requested can be sent by the Publisher so only signal demand for what can be safely handled. +

        + A Publisher can send less than is requested if the stream ends but + then must emit either Subscriber.onError(Throwable) or Subscriber.onComplete().

        +
        +
        Parameters:
        +
        n - the strictly positive number of elements to requests to the upstream Publisher
        +
        +
      • +
      + + + +
        +
      • +

        cancel

        +
        void cancel()
        +
        Request the Publisher to stop sending data and clean up resources. +

        + Data may still be sent to meet previously signalled demand after calling cancel as this request is asynchronous.

        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-frame.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-frame.html new file mode 100644 index 0000000..1e3e320 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-frame.html @@ -0,0 +1,23 @@ + + + + + + +org.reactivestreams (reactive-streams 1.0.0 API) + + + + +

org.reactivestreams

+
+

Interfaces

+ +
+ + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-summary.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-summary.html new file mode 100644 index 0000000..1810075 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-summary.html @@ -0,0 +1,160 @@ + + + + + + +org.reactivestreams (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Package org.reactivestreams

+
+
+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-tree.html b/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-tree.html new file mode 100644 index 0000000..1a0c92c --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/org/reactivestreams/package-tree.html @@ -0,0 +1,135 @@ + + + + + + +org.reactivestreams Class Hierarchy (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For Package org.reactivestreams

+
+
+

Interface Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/overview-tree.html b/reactive-streams-1.0.0-javadoc/overview-tree.html new file mode 100644 index 0000000..b006135 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/overview-tree.html @@ -0,0 +1,139 @@ + + + + + + +Class Hierarchy (reactive-streams 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For All Packages

+Package Hierarchies: + +
+
+

Interface Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-1.0.0-javadoc/package-list b/reactive-streams-1.0.0-javadoc/package-list new file mode 100644 index 0000000..6a8ba62 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/package-list @@ -0,0 +1 @@ +org.reactivestreams diff --git a/reactive-streams-1.0.0-javadoc/script.js b/reactive-streams-1.0.0-javadoc/script.js new file mode 100644 index 0000000..b346356 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/script.js @@ -0,0 +1,30 @@ +function show(type) +{ + count = 0; + for (var key in methods) { + var row = document.getElementById(key); + if ((methods[key] & type) != 0) { + row.style.display = ''; + row.className = (count++ % 2) ? rowColor : altColor; + } + else + row.style.display = 'none'; + } + updateTabs(type); +} + +function updateTabs(type) +{ + for (var value in tabs) { + var sNode = document.getElementById(tabs[value][0]); + var spanNode = sNode.firstChild; + if (value == type) { + sNode.className = activeTableTab; + spanNode.innerHTML = tabs[value][1]; + } + else { + sNode.className = tableTab; + spanNode.innerHTML = "" + tabs[value][1] + ""; + } + } +} diff --git a/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Processor.html b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Processor.html new file mode 100644 index 0000000..469913d --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Processor.html @@ -0,0 +1,83 @@ + + + +Source code + + + +
+
001package org.reactivestreams;
+002
+003/**
+004 * A Processor represents a processing stage—which is both a {@link Subscriber}
+005 * and a {@link Publisher} and obeys the contracts of both.
+006 *
+007 * @param <T> the type of element signaled to the {@link Subscriber}
+008 * @param <R> the type of element signaled by the {@link Publisher}
+009 */
+010public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
+011}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Publisher.html b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Publisher.html new file mode 100644 index 0000000..67b9089 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Publisher.html @@ -0,0 +1,101 @@ + + + +Source code + + + +
+
001package org.reactivestreams;
+002
+003/**
+004 * A {@link Publisher} is a provider of a potentially unbounded number of sequenced elements, publishing them according to
+005 * the demand received from its {@link Subscriber}(s).
+006 * <p>
+007 * A {@link Publisher} can serve multiple {@link Subscriber}s subscribed {@link #subscribe(Subscriber)} dynamically
+008 * at various points in time.
+009 *
+010 * @param <T> the type of element signaled.
+011 */
+012public interface Publisher<T> {
+013
+014    /**
+015     * Request {@link Publisher} to start streaming data.
+016     * <p>
+017     * This is a "factory method" and can be called multiple times, each time starting a new {@link Subscription}.
+018     * <p>
+019     * Each {@link Subscription} will work for only a single {@link Subscriber}.
+020     * <p>
+021     * A {@link Subscriber} should only subscribe once to a single {@link Publisher}.
+022     * <p>
+023     * If the {@link Publisher} rejects the subscription attempt or otherwise fails it will
+024     * signal the error via {@link Subscriber#onError}.
+025     *
+026     * @param s the {@link Subscriber} that will consume signals from this {@link Publisher}
+027     */
+028    public void subscribe(Subscriber<? super T> s);
+029}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscriber.html b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscriber.html new file mode 100644 index 0000000..6774538 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscriber.html @@ -0,0 +1,127 @@ + + + +Source code + + + +
+
001package org.reactivestreams;
+002
+003/**
+004 * Will receive call to {@link #onSubscribe(Subscription)} once after passing an instance of {@link Subscriber} to {@link Publisher#subscribe(Subscriber)}.
+005 * <p>
+006 * No further notifications will be received until {@link Subscription#request(long)} is called.
+007 * <p>
+008 * After signaling demand:
+009 * <ul>
+010 * <li>One or more invocations of {@link #onNext(Object)} up to the maximum number defined by {@link Subscription#request(long)}</li>
+011 * <li>Single invocation of {@link #onError(Throwable)} or {@link Subscriber#onComplete()} which signals a terminal state after which no further events will be sent.
+012 * </ul>
+013 * <p>
+014 * Demand can be signaled via {@link Subscription#request(long)} whenever the {@link Subscriber} instance is capable of handling more.
+015 *
+016 * @param <T> the type of element signaled.
+017 */
+018public interface Subscriber<T> {
+019    /**
+020     * Invoked after calling {@link Publisher#subscribe(Subscriber)}.
+021     * <p>
+022     * No data will start flowing until {@link Subscription#request(long)} is invoked.
+023     * <p>
+024     * It is the responsibility of this {@link Subscriber} instance to call {@link Subscription#request(long)} whenever more data is wanted.
+025     * <p>
+026     * The {@link Publisher} will send notifications only in response to {@link Subscription#request(long)}.
+027     * 
+028     * @param s
+029     *            {@link Subscription} that allows requesting data via {@link Subscription#request(long)}
+030     */
+031    public void onSubscribe(Subscription s);
+032
+033    /**
+034     * Data notification sent by the {@link Publisher} in response to requests to {@link Subscription#request(long)}.
+035     * 
+036     * @param t the element signaled
+037     */
+038    public void onNext(T t);
+039
+040    /**
+041     * Failed terminal state.
+042     * <p>
+043     * No further events will be sent even if {@link Subscription#request(long)} is invoked again.
+044     *
+045     * @param t the throwable signaled
+046     */
+047    public void onError(Throwable t);
+048
+049    /**
+050     * Successful terminal state.
+051     * <p>
+052     * No further events will be sent even if {@link Subscription#request(long)} is invoked again.
+053     */
+054    public void onComplete();
+055}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscription.html b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscription.html new file mode 100644 index 0000000..900f6d4 --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/src-html/org/reactivestreams/Subscription.html @@ -0,0 +1,105 @@ + + + +Source code + + + +
+
001package org.reactivestreams;
+002
+003/**
+004 * A {@link Subscription} represents a one-to-one lifecycle of a {@link Subscriber} subscribing to a {@link Publisher}.
+005 * <p>
+006 * It can only be used once by a single {@link Subscriber}.
+007 * <p>
+008 * It is used to both signal desire for data and cancel demand (and allow resource cleanup).
+009 *
+010 */
+011public interface Subscription {
+012    /**
+013     * No events will be sent by a {@link Publisher} until demand is signaled via this method.
+014     * <p>
+015     * It can be called however often and whenever needed—but the outstanding cumulative demand must never exceed Long.MAX_VALUE.
+016     * An outstanding cumulative demand of Long.MAX_VALUE may be treated by the {@link Publisher} as "effectively unbounded".
+017     * <p>
+018     * Whatever has been requested can be sent by the {@link Publisher} so only signal demand for what can be safely handled.
+019     * <p>
+020     * A {@link Publisher} can send less than is requested if the stream ends but
+021     * then must emit either {@link Subscriber#onError(Throwable)} or {@link Subscriber#onComplete()}.
+022     * 
+023     * @param n the strictly positive number of elements to requests to the upstream {@link Publisher}
+024     */
+025    public void request(long n);
+026
+027    /**
+028     * Request the {@link Publisher} to stop sending data and clean up resources.
+029     * <p>
+030     * Data may still be sent to meet previously signalled demand after calling cancel as this request is asynchronous.
+031     */
+032    public void cancel();
+033}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-1.0.0-javadoc/stylesheet.css b/reactive-streams-1.0.0-javadoc/stylesheet.css new file mode 100644 index 0000000..cebb4fd --- /dev/null +++ b/reactive-streams-1.0.0-javadoc/stylesheet.css @@ -0,0 +1,574 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + +@import url('resources/fonts/dejavu.css'); + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D7A97; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D7A97; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D7A97; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; + width:100%; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} diff --git a/reactive-streams-examples-1.0.0-javadoc/allclasses-frame.html b/reactive-streams-examples-1.0.0-javadoc/allclasses-frame.html new file mode 100644 index 0000000..24a8dee --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/allclasses-frame.html @@ -0,0 +1,23 @@ + + + + + + +All Classes (reactive-streams-examples 1.0.0 API) + + + + +

All Classes

+
+ +
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/allclasses-noframe.html b/reactive-streams-examples-1.0.0-javadoc/allclasses-noframe.html new file mode 100644 index 0000000..168d4c0 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/allclasses-noframe.html @@ -0,0 +1,23 @@ + + + + + + +All Classes (reactive-streams-examples 1.0.0 API) + + + + +

All Classes

+
+ +
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/constant-values.html b/reactive-streams-examples-1.0.0-javadoc/constant-values.html new file mode 100644 index 0000000..1905249 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/constant-values.html @@ -0,0 +1,120 @@ + + + + + + +Constant Field Values (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Constant Field Values

+

Contents

+
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/deprecated-list.html b/reactive-streams-examples-1.0.0-javadoc/deprecated-list.html new file mode 100644 index 0000000..765eb9d --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/deprecated-list.html @@ -0,0 +1,120 @@ + + + + + + +Deprecated List (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Deprecated API

+

Contents

+
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/help-doc.html b/reactive-streams-examples-1.0.0-javadoc/help-doc.html new file mode 100644 index 0000000..83caaa0 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/help-doc.html @@ -0,0 +1,217 @@ + + + + + + +API Help (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

How This API Document Is Organized

+
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
+
+
+ +This help file applies to API documentation generated using the standard doclet.
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/index-all.html b/reactive-streams-examples-1.0.0-javadoc/index-all.html new file mode 100644 index 0000000..edfa0c4 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/index-all.html @@ -0,0 +1,229 @@ + + + + + + +Index (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
A F I N O R S W  + + +

A

+
+
AsyncIterablePublisher<T> - Class in org.reactivestreams.example.unicast
+
+
AsyncIterablePublisher is an implementation of Reactive Streams `Publisher` + which executes asynchronously, using a provided `Executor` and produces elements + from a given `Iterable` in a "unicast" configuration to its `Subscribers`.
+
+
AsyncIterablePublisher(Iterable<T>, Executor) - Constructor for class org.reactivestreams.example.unicast.AsyncIterablePublisher
+
 
+
AsyncIterablePublisher(Iterable<T>, int, Executor) - Constructor for class org.reactivestreams.example.unicast.AsyncIterablePublisher
+
 
+
AsyncSubscriber<T> - Class in org.reactivestreams.example.unicast
+
+
AsyncSubscriber is an implementation of Reactive Streams `Subscriber`, + it runs asynchronously (on an Executor), requests one element + at a time, and invokes a user-defined method to process each element.
+
+
AsyncSubscriber(Executor) - Constructor for class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
+ + + +

F

+
+
foreach(T) - Method in class org.reactivestreams.example.unicast.SyncSubscriber
+
 
+
+ + + +

I

+
+
InfiniteIncrementNumberPublisher - Class in org.reactivestreams.example.unicast
+
 
+
InfiniteIncrementNumberPublisher(Executor) - Constructor for class org.reactivestreams.example.unicast.InfiniteIncrementNumberPublisher
+
 
+
+ + + +

N

+
+
NumberIterablePublisher - Class in org.reactivestreams.example.unicast
+
 
+
NumberIterablePublisher(int, int, Executor) - Constructor for class org.reactivestreams.example.unicast.NumberIterablePublisher
+
 
+
+ + + +

O

+
+
onComplete() - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
onComplete() - Method in class org.reactivestreams.example.unicast.SyncSubscriber
+
 
+
onError(Throwable) - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
onError(Throwable) - Method in class org.reactivestreams.example.unicast.SyncSubscriber
+
 
+
onNext(T) - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
onNext(T) - Method in class org.reactivestreams.example.unicast.SyncSubscriber
+
 
+
onSubscribe(Subscription) - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
onSubscribe(Subscription) - Method in class org.reactivestreams.example.unicast.SyncSubscriber
+
 
+
org.reactivestreams.example.unicast - package org.reactivestreams.example.unicast
+
 
+
+ + + +

R

+
+
run() - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
+ + + +

S

+
+
subscribe(Subscriber<? super T>) - Method in class org.reactivestreams.example.unicast.AsyncIterablePublisher
+
 
+
SyncSubscriber<T> - Class in org.reactivestreams.example.unicast
+
+
SyncSubscriber is an implementation of Reactive Streams `Subscriber`, + it runs synchronously (on the Publisher's thread) and requests one element + at a time and invokes a user-defined method to process each element.
+
+
SyncSubscriber() - Constructor for class org.reactivestreams.example.unicast.SyncSubscriber
+
 
+
+ + + +

W

+
+
whenComplete() - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
whenError(Throwable) - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
whenNext(T) - Method in class org.reactivestreams.example.unicast.AsyncSubscriber
+
 
+
+A F I N O R S W 
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/index.html b/reactive-streams-examples-1.0.0-javadoc/index.html new file mode 100644 index 0000000..34bfd60 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/index.html @@ -0,0 +1,72 @@ + + + + + + +reactive-streams-examples 1.0.0 API + + + + + + +<noscript> +<div>JavaScript is disabled on your browser.</div> +</noscript> +<h2>Frame Alert</h2> +<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="org/reactivestreams/example/unicast/package-summary.html">Non-frame version</a>.</p> + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncIterablePublisher.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncIterablePublisher.html new file mode 100644 index 0000000..02d6714 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncIterablePublisher.html @@ -0,0 +1,303 @@ + + + + + + +AsyncIterablePublisher (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.example.unicast
+

Class AsyncIterablePublisher<T>

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    org.reactivestreams.Publisher<T>
    +
    +
    +
    Direct Known Subclasses:
    +
    InfiniteIncrementNumberPublisher, NumberIterablePublisher
    +
    +
    +
    +
    public class AsyncIterablePublisher<T>
    +extends java.lang.Object
    +implements org.reactivestreams.Publisher<T>
    +
    AsyncIterablePublisher is an implementation of Reactive Streams `Publisher` + which executes asynchronously, using a provided `Executor` and produces elements + from a given `Iterable` in a "unicast" configuration to its `Subscribers`. + + NOTE: The code below uses a lot of try-catches to show the reader where exceptions can be expected, and where they are forbidden.
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + + +
      Constructors 
      Constructor and Description
      AsyncIterablePublisher(java.lang.Iterable<T> elements, + java.util.concurrent.Executor executor) 
      AsyncIterablePublisher(java.lang.Iterable<T> elements, + int batchSize, + java.util.concurrent.Executor executor) 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + +
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      voidsubscribe(org.reactivestreams.Subscriber<? super T> s) 
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        AsyncIterablePublisher

        +
        public AsyncIterablePublisher(java.lang.Iterable<T> elements,
        +                              java.util.concurrent.Executor executor)
        +
      • +
      + + + +
        +
      • +

        AsyncIterablePublisher

        +
        public AsyncIterablePublisher(java.lang.Iterable<T> elements,
        +                              int batchSize,
        +                              java.util.concurrent.Executor executor)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        subscribe

        +
        public void subscribe(org.reactivestreams.Subscriber<? super T> s)
        +
        +
        Specified by:
        +
        subscribe in interface org.reactivestreams.Publisher<T>
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncSubscriber.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncSubscriber.html new file mode 100644 index 0000000..736f2e8 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/AsyncSubscriber.html @@ -0,0 +1,394 @@ + + + + + + +AsyncSubscriber (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.example.unicast
+

Class AsyncSubscriber<T>

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    java.lang.Runnable, org.reactivestreams.Subscriber<T>
    +
    +
    +
    +
    public abstract class AsyncSubscriber<T>
    +extends java.lang.Object
    +implements org.reactivestreams.Subscriber<T>, java.lang.Runnable
    +
    AsyncSubscriber is an implementation of Reactive Streams `Subscriber`, + it runs asynchronously (on an Executor), requests one element + at a time, and invokes a user-defined method to process each element. + + NOTE: The code below uses a lot of try-catches to show the reader where exceptions can be expected, and where they are forbidden.
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + + +
      Constructors 
      ModifierConstructor and Description
      protected AsyncSubscriber(java.util.concurrent.Executor executor) 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Abstract Methods Concrete Methods 
      Modifier and TypeMethod and Description
      voidonComplete() 
      voidonError(java.lang.Throwable t) 
      voidonNext(T element) 
      voidonSubscribe(org.reactivestreams.Subscription s) 
      voidrun() 
      protected voidwhenComplete() 
      protected voidwhenError(java.lang.Throwable error) 
      protected abstract booleanwhenNext(T element) 
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        AsyncSubscriber

        +
        protected AsyncSubscriber(java.util.concurrent.Executor executor)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + + + +
        +
      • +

        whenNext

        +
        protected abstract boolean whenNext(T element)
        +
      • +
      + + + + + + + +
        +
      • +

        whenError

        +
        protected void whenError(java.lang.Throwable error)
        +
      • +
      + + + +
        +
      • +

        onSubscribe

        +
        public final void onSubscribe(org.reactivestreams.Subscription s)
        +
        +
        Specified by:
        +
        onSubscribe in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + + + +
        +
      • +

        onNext

        +
        public final void onNext(T element)
        +
        +
        Specified by:
        +
        onNext in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onError

        +
        public final void onError(java.lang.Throwable t)
        +
        +
        Specified by:
        +
        onError in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onComplete

        +
        public final void onComplete()
        +
        +
        Specified by:
        +
        onComplete in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        run

        +
        public final void run()
        +
        +
        Specified by:
        +
        run in interface java.lang.Runnable
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html new file mode 100644 index 0000000..1ff28dd --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html @@ -0,0 +1,249 @@ + + + + + + +InfiniteIncrementNumberPublisher (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.example.unicast
+

Class InfiniteIncrementNumberPublisher

+
+
+ +
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Summary

      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/NumberIterablePublisher.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/NumberIterablePublisher.html new file mode 100644 index 0000000..6aece22 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/NumberIterablePublisher.html @@ -0,0 +1,253 @@ + + + + + + +NumberIterablePublisher (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.example.unicast
+

Class NumberIterablePublisher

+
+
+ +
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      NumberIterablePublisher(int from, + int to, + java.util.concurrent.Executor executor) 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        NumberIterablePublisher

        +
        public NumberIterablePublisher(int from,
        +                               int to,
        +                               java.util.concurrent.Executor executor)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/SyncSubscriber.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/SyncSubscriber.html new file mode 100644 index 0000000..4255a79 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/SyncSubscriber.html @@ -0,0 +1,349 @@ + + + + + + +SyncSubscriber (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.example.unicast
+

Class SyncSubscriber<T>

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    org.reactivestreams.Subscriber<T>
    +
    +
    +
    +
    public abstract class SyncSubscriber<T>
    +extends java.lang.Object
    +implements org.reactivestreams.Subscriber<T>
    +
    SyncSubscriber is an implementation of Reactive Streams `Subscriber`, + it runs synchronously (on the Publisher's thread) and requests one element + at a time and invokes a user-defined method to process each element. + + NOTE: The code below uses a lot of try-catches to show the reader where exceptions can be expected, and where they are forbidden.
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      SyncSubscriber() 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Abstract Methods Concrete Methods 
      Modifier and TypeMethod and Description
      protected abstract booleanforeach(T element) 
      voidonComplete() 
      voidonError(java.lang.Throwable t) 
      voidonNext(T element) 
      voidonSubscribe(org.reactivestreams.Subscription s) 
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        onSubscribe

        +
        public void onSubscribe(org.reactivestreams.Subscription s)
        +
        +
        Specified by:
        +
        onSubscribe in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + + + +
        +
      • +

        onNext

        +
        public void onNext(T element)
        +
        +
        Specified by:
        +
        onNext in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + + + +
        +
      • +

        foreach

        +
        protected abstract boolean foreach(T element)
        +
      • +
      + + + +
        +
      • +

        onError

        +
        public void onError(java.lang.Throwable t)
        +
        +
        Specified by:
        +
        onError in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onComplete

        +
        public void onComplete()
        +
        +
        Specified by:
        +
        onComplete in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-frame.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-frame.html new file mode 100644 index 0000000..afd557d --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-frame.html @@ -0,0 +1,24 @@ + + + + + + +org.reactivestreams.example.unicast (reactive-streams-examples 1.0.0 API) + + + + +

org.reactivestreams.example.unicast

+
+

Classes

+ +
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-summary.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-summary.html new file mode 100644 index 0000000..2b906a5 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-summary.html @@ -0,0 +1,166 @@ + + + + + + +org.reactivestreams.example.unicast (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Package org.reactivestreams.example.unicast

+
+
+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-tree.html b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-tree.html new file mode 100644 index 0000000..d72bbbe --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/org/reactivestreams/example/unicast/package-tree.html @@ -0,0 +1,136 @@ + + + + + + +org.reactivestreams.example.unicast Class Hierarchy (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For Package org.reactivestreams.example.unicast

+
+
+

Class Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/overview-tree.html b/reactive-streams-examples-1.0.0-javadoc/overview-tree.html new file mode 100644 index 0000000..51dfaf1 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/overview-tree.html @@ -0,0 +1,140 @@ + + + + + + +Class Hierarchy (reactive-streams-examples 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For All Packages

+Package Hierarchies: + +
+
+

Class Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-examples-1.0.0-javadoc/package-list b/reactive-streams-examples-1.0.0-javadoc/package-list new file mode 100644 index 0000000..bbcbda0 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/package-list @@ -0,0 +1 @@ +org.reactivestreams.example.unicast diff --git a/reactive-streams-examples-1.0.0-javadoc/script.js b/reactive-streams-examples-1.0.0-javadoc/script.js new file mode 100644 index 0000000..b346356 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/script.js @@ -0,0 +1,30 @@ +function show(type) +{ + count = 0; + for (var key in methods) { + var row = document.getElementById(key); + if ((methods[key] & type) != 0) { + row.style.display = ''; + row.className = (count++ % 2) ? rowColor : altColor; + } + else + row.style.display = 'none'; + } + updateTabs(type); +} + +function updateTabs(type) +{ + for (var value in tabs) { + var sNode = document.getElementById(tabs[value][0]); + var spanNode = sNode.firstChild; + if (value == type) { + sNode.className = activeTableTab; + spanNode.innerHTML = tabs[value][1]; + } + else { + sNode.className = tableTab; + spanNode.innerHTML = "" + tabs[value][1] + ""; + } + } +} diff --git a/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncIterablePublisher.html b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncIterablePublisher.html new file mode 100644 index 0000000..bd61dc2 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncIterablePublisher.html @@ -0,0 +1,330 @@ + + + +Source code + + + +
+
001package org.reactivestreams.example.unicast;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006
+007import java.util.Iterator;
+008import java.util.Collections;
+009import java.util.concurrent.Executor;
+010import java.util.concurrent.atomic.AtomicBoolean;
+011import java.util.concurrent.ConcurrentLinkedQueue;
+012
+013/**
+014 * AsyncIterablePublisher is an implementation of Reactive Streams `Publisher`
+015 * which executes asynchronously, using a provided `Executor` and produces elements
+016 * from a given `Iterable` in a "unicast" configuration to its `Subscribers`.
+017 *
+018 * NOTE: The code below uses a lot of try-catches to show the reader where exceptions can be expected, and where they are forbidden.
+019 */
+020public class AsyncIterablePublisher<T> implements Publisher<T> {
+021  private final static int DEFAULT_BATCHSIZE = 1024;
+022
+023  private final Iterable<T> elements; // This is our data source / generator
+024  private final Executor executor; // This is our thread pool, which will make sure that our Publisher runs asynchronously to its Subscribers
+025  private final int batchSize; // In general, if one uses an `Executor`, one should be nice nad not hog a thread for too long, this is the cap for that, in elements
+026
+027  public AsyncIterablePublisher(final Iterable<T> elements, final Executor executor) {
+028    this(elements, DEFAULT_BATCHSIZE, executor);
+029  }
+030
+031  public AsyncIterablePublisher(final Iterable<T> elements, final int batchSize, final Executor executor) {
+032    if (elements == null) throw null;
+033    if (executor == null) throw null;
+034    if (batchSize < 1) throw new IllegalArgumentException("batchSize must be greater than zero!");
+035    this.elements = elements;
+036    this.executor = executor;
+037    this.batchSize = batchSize;
+038  }
+039
+040  @Override
+041  public void subscribe(final Subscriber<? super T> s) {
+042    // As per rule 1.11, we have decided to support multiple subscribers in a unicast configuration
+043    // for this `Publisher` implementation.
+044    // As per 2.13, this method must return normally (i.e. not throw)
+045    new SubscriptionImpl(s).init();
+046  }
+047
+048  // These represent the protocol of the `AsyncIterablePublishers` SubscriptionImpls
+049  static interface Signal {};
+050  enum Cancel implements Signal { Instance; };
+051  enum Subscribe implements Signal { Instance; };
+052  enum Send implements Signal { Instance; };
+053  static final class Request implements Signal {
+054    final long n;
+055    Request(final long n) {
+056      this.n = n;
+057    }
+058  };
+059
+060  // This is our implementation of the Reactive Streams `Subscription`,
+061  // which represents the association between a `Publisher` and a `Subscriber`.
+062  final class SubscriptionImpl implements Subscription, Runnable {
+063    final Subscriber<? super T> subscriber; // We need a reference to the `Subscriber` so we can talk to it
+064    private boolean cancelled = false; // This flag will track whether this `Subscription` is to be considered cancelled or not
+065    private long demand = 0; // Here we track the current demand, i.e. what has been requested but not yet delivered
+066    private Iterator<T> iterator; // This is our cursor into the data stream, which we will send to the `Subscriber`
+067
+068    SubscriptionImpl(final Subscriber<? super T> subscriber) {
+069      // As per rule 1.09, we need to throw a `java.lang.NullPointerException` if the `Subscriber` is `null`
+070      if (subscriber == null) throw null;
+071      this.subscriber = subscriber;
+072    }
+073
+074    // This `ConcurrentLinkedQueue` will track signals that are sent to this `Subscription`, like `request` and `cancel`
+075    private final ConcurrentLinkedQueue<Signal> inboundSignals = new ConcurrentLinkedQueue<Signal>();
+076
+077    // We are using this `AtomicBoolean` to make sure that this `Subscription` doesn't run concurrently with itself,
+078    // which would violate rule 1.3 among others (no concurrent notifications).
+079    private final AtomicBoolean on = new AtomicBoolean(false);
+080
+081    // This method will register inbound demand from our `Subscriber` and validate it against rule 3.9 and rule 3.17
+082    private void doRequest(final long n) {
+083      if (n < 1)
+084        terminateDueTo(new IllegalArgumentException(subscriber + " violated the Reactive Streams rule 3.9 by requesting a non-positive number of elements."));
+085      else if (demand + n < 1) {
+086        // As governed by rule 3.17, when demand overflows `Long.MAX_VALUE` we treat the signalled demand as "effectively unbounded"
+087        demand = Long.MAX_VALUE;  // Here we protect from the overflow and treat it as "effectively unbounded"
+088        doSend(); // Then we proceed with sending data downstream
+089      } else {
+090        demand += n; // Here we record the downstream demand
+091        doSend(); // Then we can proceed with sending data downstream
+092      }
+093    }
+094
+095    // This handles cancellation requests, and is idempotent, thread-safe and not synchronously performing heavy computations as specified in rule 3.5
+096    private void doCancel() {
+097      cancelled = true;
+098    }
+099
+100    // Instead of executing `subscriber.onSubscribe` synchronously from within `Publisher.subscribe`
+101    // we execute it asynchronously, this is to avoid executing the user code (`Iterable.iterator`) on the calling thread.
+102    // It also makes it easier to follow rule 1.9
+103    private void doSubscribe() {
+104      try {
+105        iterator = elements.iterator();
+106        if (iterator == null)
+107          iterator = Collections.<T>emptyList().iterator(); // So we can assume that `iterator` is never null
+108      } catch(final Throwable t) {
+109        subscriber.onSubscribe(new Subscription() { // We need to make sure we signal onSubscribe before onError, obeying rule 1.9
+110          @Override public void cancel() {}
+111          @Override public void request(long n) {}
+112        });
+113        terminateDueTo(t); // Here we send onError, obeying rule 1.09
+114      }
+115
+116      if (!cancelled) {
+117        // Deal with setting up the subscription with the subscriber
+118        try {
+119          subscriber.onSubscribe(this);
+120        } catch(final Throwable t) { // Due diligence to obey 2.13
+121          terminateDueTo(new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onSubscribe.", t));
+122        }
+123
+124        // Deal with already complete iterators promptly
+125        boolean hasElements = false;
+126        try {
+127          hasElements = iterator.hasNext();
+128        } catch(final Throwable t) {
+129          terminateDueTo(t); // If hasNext throws, there's something wrong and we need to signal onError as per 1.2, 1.4, 
+130        }
+131
+132        // If we don't have anything to deliver, we're already done, so lets do the right thing and
+133        // not wait for demand to deliver `onComplete` as per rule 1.2 and 1.3
+134        if (!hasElements) {
+135          try {
+136            doCancel(); // Rule 1.6 says we need to consider the `Subscription` cancelled when `onComplete` is signalled
+137            subscriber.onComplete();
+138          } catch(final Throwable t) { // As per rule 2.13, `onComplete` is not allowed to throw exceptions, so we do what we can, and log this.
+139            (new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onComplete.", t)).printStackTrace(System.err);
+140          }
+141        }
+142      }
+143    }
+144
+145    // This is our behavior for producing elements downstream
+146    private void doSend() {
+147      try {
+148        // In order to play nice with the `Executor` we will only send at-most `batchSize` before
+149        // rescheduing ourselves and relinquishing the current thread.
+150        int leftInBatch = batchSize;
+151        do {
+152          T next;
+153          boolean hasNext;
+154          try {
+155            next = iterator.next(); // We have already checked `hasNext` when subscribing, so we can fall back to testing -after- `next` is called.
+156            hasNext = iterator.hasNext(); // Need to keep track of End-of-Stream
+157          } catch (final Throwable t) {
+158            terminateDueTo(t); // If `next` or `hasNext` throws (they can, since it is user-provided), we need to treat the stream as errored as per rule 1.4
+159            return;
+160          }
+161          subscriber.onNext(next); // Then we signal the next element downstream to the `Subscriber`
+162          if (!hasNext) { // If we are at End-of-Stream
+163            doCancel(); // We need to consider this `Subscription` as cancelled as per rule 1.6
+164            subscriber.onComplete(); // Then we signal `onComplete` as per rule 1.2 and 1.5
+165          }
+166        } while (!cancelled           // This makes sure that rule 1.8 is upheld, i.e. we need to stop signalling "eventually"
+167                 && --leftInBatch > 0 // This makes sure that we only send `batchSize` number of elements in one go (so we can yield to other Runnables)
+168                 && --demand > 0);    // This makes sure that rule 1.1 is upheld (sending more than was demanded)
+169
+170        if (!cancelled && demand > 0) // If the `Subscription` is still alive and well, and we have demand to satisfy, we signal ourselves to send more data
+171          signal(Send.Instance);
+172      } catch(final Throwable t) {
+173        // We can only get here if `onNext` or `onComplete` threw, and they are not allowed to according to 2.13, so we can only cancel and log here.
+174        doCancel(); // Make sure that we are cancelled, since we cannot do anything else since the `Subscriber` is faulty.
+175        (new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onNext or onComplete.", t)).printStackTrace(System.err);
+176      }
+177    }
+178
+179    // This is a helper method to ensure that we always `cancel` when we signal `onError` as per rule 1.6
+180    private void terminateDueTo(final Throwable t) {
+181      cancelled = true; // When we signal onError, the subscription must be considered as cancelled, as per rule 1.6
+182      try {
+183        subscriber.onError(t); // Then we signal the error downstream, to the `Subscriber`
+184      } catch(final Throwable t2) { // If `onError` throws an exception, this is a spec violation according to rule 1.9, and all we can do is to log it.
+185        (new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onError.", t2)).printStackTrace(System.err);
+186      }
+187    }
+188
+189    // What `signal` does is that it sends signals to the `Subscription` asynchronously
+190    private void signal(final Signal signal) {
+191      if (inboundSignals.offer(signal)) // No need to null-check here as ConcurrentLinkedQueue does this for us
+192        tryScheduleToExecute(); // Then we try to schedule it for execution, if it isn't already
+193    }
+194
+195    // This is the main "event loop" if you so will
+196    @Override public final void run() {
+197      if(on.get()) { // establishes a happens-before relationship with the end of the previous run
+198        try {
+199          final Signal s = inboundSignals.poll(); // We take a signal off the queue
+200          if (!cancelled) { // to make sure that we follow rule 1.8, 3.6 and 3.7
+201
+202            // Below we simply unpack the `Signal`s and invoke the corresponding methods
+203            if (s instanceof Request)
+204              doRequest(((Request)s).n);
+205            else if (s == Send.Instance)
+206              doSend();
+207            else if (s == Cancel.Instance)
+208              doCancel();
+209            else if (s == Subscribe.Instance)
+210              doSubscribe();
+211          }
+212        } finally {
+213          on.set(false); // establishes a happens-before relationship with the beginning of the next run
+214          if(!inboundSignals.isEmpty()) // If we still have signals to process
+215            tryScheduleToExecute(); // Then we try to schedule ourselves to execute again
+216        }
+217      }
+218    }
+219
+220    // This method makes sure that this `Subscription` is only running on one Thread at a time,
+221    // this is important to make sure that we follow rule 1.3
+222    private final void tryScheduleToExecute() {
+223      if(on.compareAndSet(false, true)) {
+224        try {
+225          executor.execute(this);
+226        } catch(Throwable t) { // If we can't run on the `Executor`, we need to fail gracefully
+227          if (!cancelled) {
+228            doCancel(); // First of all, this failure is not recoverable, so we need to follow rule 1.4 and 1.6
+229            try {
+230              terminateDueTo(new IllegalStateException("Publisher terminated due to unavailable Executor.", t));
+231            } finally {
+232              inboundSignals.clear(); // We're not going to need these anymore
+233              // This subscription is cancelled by now, but letting it become schedulable again means
+234              // that we can drain the inboundSignals queue if anything arrives after clearing
+235              on.set(false);
+236            }
+237          }
+238        }
+239      }
+240    }
+241
+242    // Our implementation of `Subscription.request` sends a signal to the Subscription that more elements are in demand
+243    @Override public void request(final long n) {
+244      signal(new Request(n));
+245    }
+246    // Our implementation of `Subscription.cancel` sends a signal to the Subscription that the `Subscriber` is not interested in any more elements
+247    @Override public void cancel() {
+248      signal(Cancel.Instance);
+249    }
+250    // The reason for the `init` method is that we want to ensure the `SubscriptionImpl`
+251    // is completely constructed before it is exposed to the thread pool, therefor this
+252    // method is only intended to be invoked once, and immediately after the constructor has
+253    // finished.
+254    void init() {
+255      signal(Subscribe.Instance);
+256    }
+257  };
+258}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncSubscriber.html b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncSubscriber.html new file mode 100644 index 0000000..83cbc70 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/AsyncSubscriber.html @@ -0,0 +1,310 @@ + + + +Source code + + + +
+
001package org.reactivestreams.example.unicast;
+002
+003import org.reactivestreams.Subscriber;
+004import org.reactivestreams.Subscription;
+005
+006import java.util.concurrent.Executor;
+007import java.util.concurrent.atomic.AtomicBoolean;
+008import java.util.concurrent.ConcurrentLinkedQueue;
+009
+010/**
+011 * AsyncSubscriber is an implementation of Reactive Streams `Subscriber`,
+012 * it runs asynchronously (on an Executor), requests one element
+013 * at a time, and invokes a user-defined method to process each element.
+014 *
+015 * NOTE: The code below uses a lot of try-catches to show the reader where exceptions can be expected, and where they are forbidden.
+016 */
+017public abstract class AsyncSubscriber<T> implements Subscriber<T>, Runnable {
+018
+019  // Signal represents the asynchronous protocol between the Publisher and Subscriber
+020  private static interface Signal {}
+021
+022  private enum OnComplete implements Signal { Instance; }
+023
+024  private static class OnError implements Signal {
+025    public final Throwable error;
+026    public OnError(final Throwable error) { this.error = error; }
+027  }
+028
+029  private static class OnNext<T> implements Signal {
+030    public final T next;
+031    public OnNext(final T next) { this.next = next; }
+032  }
+033
+034  private static class OnSubscribe implements Signal {
+035    public final Subscription subscription;
+036    public OnSubscribe(final Subscription subscription) { this.subscription = subscription; }
+037  }
+038
+039  private Subscription subscription; // Obeying rule 3.1, we make this private!
+040  private boolean done; // It's useful to keep track of whether this Subscriber is done or not
+041  private final Executor executor; // This is the Executor we'll use to be asynchronous, obeying rule 2.2
+042
+043  // Only one constructor, and it's only accessible for the subclasses
+044  protected AsyncSubscriber(Executor executor) {
+045    if (executor == null) throw null;
+046    this.executor = executor;
+047  }
+048
+049  // Showcases a convenience method to idempotently marking the Subscriber as "done", so we don't want to process more elements
+050  // herefor we also need to cancel our `Subscription`.
+051  private final void done() {
+052    //On this line we could add a guard against `!done`, but since rule 3.7 says that `Subscription.cancel()` is idempotent, we don't need to.
+053    done = true; // If we `foreach` throws an exception, let's consider ourselves done (not accepting more elements)
+054    if (subscription != null) { // If we are bailing out before we got a `Subscription` there's little need for cancelling it.
+055      try {
+056        subscription.cancel(); // Cancel the subscription
+057      } catch(final Throwable t) {
+058        //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+059        (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+060      }
+061    }
+062  }
+063
+064  // This method is invoked when the OnNext signals arrive
+065  // Returns whether more elements are desired or not, and if no more elements are desired,
+066  // for convenience.
+067  protected abstract boolean whenNext(final T element);
+068
+069  // This method is invoked when the OnComplete signal arrives
+070  // override this method to implement your own custom onComplete logic.
+071  protected void whenComplete() { }
+072
+073  // This method is invoked if the OnError signal arrives
+074  // override this method to implement your own custom onError logic.
+075  protected void whenError(Throwable error) { }
+076
+077  private final void handleOnSubscribe(final Subscription s) {
+078    if (s == null) {
+079      // Getting a null `Subscription` here is not valid so lets just ignore it.
+080    } else if (subscription != null) { // If someone has made a mistake and added this Subscriber multiple times, let's handle it gracefully
+081      try {
+082        s.cancel(); // Cancel the additional subscription to follow rule 2.5
+083      } catch(final Throwable t) {
+084        //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+085        (new IllegalStateException(s + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+086      }
+087    } else {
+088      // We have to assign it locally before we use it, if we want to be a synchronous `Subscriber`
+089      // Because according to rule 3.10, the Subscription is allowed to call `onNext` synchronously from within `request`
+090      subscription = s;
+091      try {
+092        // If we want elements, according to rule 2.1 we need to call `request`
+093        // And, according to rule 3.2 we are allowed to call this synchronously from within the `onSubscribe` method
+094        s.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+095      } catch(final Throwable t) {
+096        // Subscription.request is not allowed to throw according to rule 3.16
+097        (new IllegalStateException(s + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+098      }
+099    }
+100  }
+101
+102  private final void handleOnNext(final T element) {
+103    if (!done) { // If we aren't already done
+104      if(subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+105        // Check for spec violation of 2.1 and 1.09
+106        (new IllegalStateException("Someone violated the Reactive Streams rule 1.09 and 2.1 by signalling OnNext before `Subscription.request`. (no Subscription)")).printStackTrace(System.err);
+107      } else {
+108        try {
+109          if (whenNext(element)) {
+110            try {
+111              subscription.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+112            } catch(final Throwable t) {
+113              // Subscription.request is not allowed to throw according to rule 3.16
+114              (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+115            }
+116          } else {
+117            done(); // This is legal according to rule 2.6
+118          }
+119        } catch(final Throwable t) {
+120          done();
+121          try {  
+122            onError(t);
+123          } catch(final Throwable t2) {
+124            //Subscriber.onError is not allowed to throw an exception, according to rule 2.13
+125            (new IllegalStateException(this + " violated the Reactive Streams rule 2.13 by throwing an exception from onError.", t2)).printStackTrace(System.err);
+126          }
+127        }
+128      }
+129    }
+130  }
+131
+132  // Here it is important that we do not violate 2.2 and 2.3 by calling methods on the `Subscription` or `Publisher`
+133  private void handleOnComplete() {
+134    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+135      // Publisher is not allowed to signal onComplete before onSubscribe according to rule 1.09
+136      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onComplete prior to onSubscribe.")).printStackTrace(System.err);
+137    } else {
+138      done = true; // Obey rule 2.4
+139      whenComplete();
+140    }
+141  }
+142
+143  // Here it is important that we do not violate 2.2 and 2.3 by calling methods on the `Subscription` or `Publisher`
+144  private void handleOnError(final Throwable error) {
+145    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+146      // Publisher is not allowed to signal onError before onSubscribe according to rule 1.09
+147      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onError prior to onSubscribe.")).printStackTrace(System.err);
+148    } else {
+149      done = true; // Obey rule 2.4
+150      whenError(error);
+151    }
+152  }
+153
+154  // We implement the OnX methods on `Subscriber` to send Signals that we will process asycnhronously, but only one at a time
+155
+156  @Override public final void onSubscribe(final Subscription s) {
+157    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Subscription` is `null`
+158    if (s == null) throw null;
+159
+160    signal(new OnSubscribe(s));
+161  }
+162
+163  @Override public final void onNext(final T element) {
+164    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `element` is `null`
+165    if (element == null) throw null;
+166
+167    signal(new OnNext<T>(element));
+168  }
+169
+170  @Override public final void onError(final Throwable t) {
+171    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Throwable` is `null`
+172    if (t == null) throw null;
+173
+174    signal(new OnError(t));
+175  }
+176
+177  @Override public final void onComplete() {
+178     signal(OnComplete.Instance);
+179  }
+180
+181  // This `ConcurrentLinkedQueue` will track signals that are sent to this `Subscriber`, like `OnComplete` and `OnNext` ,
+182  // and obeying rule 2.11
+183  private final ConcurrentLinkedQueue<Signal> inboundSignals = new ConcurrentLinkedQueue<Signal>();
+184
+185  // We are using this `AtomicBoolean` to make sure that this `Subscriber` doesn't run concurrently with itself,
+186  // obeying rule 2.7 and 2.11
+187  private final AtomicBoolean on = new AtomicBoolean(false);
+188
+189   @SuppressWarnings("unchecked")
+190   @Override public final void run() {
+191    if(on.get()) { // establishes a happens-before relationship with the end of the previous run
+192      try {
+193        final Signal s = inboundSignals.poll(); // We take a signal off the queue
+194        if (!done) { // If we're done, we shouldn't process any more signals, obeying rule 2.8
+195          // Below we simply unpack the `Signal`s and invoke the corresponding methods
+196          if (s instanceof OnNext<?>)
+197            handleOnNext(((OnNext<T>)s).next);
+198          else if (s instanceof OnSubscribe)
+199            handleOnSubscribe(((OnSubscribe)s).subscription);
+200          else if (s instanceof OnError) // We are always able to handle OnError, obeying rule 2.10
+201            handleOnError(((OnError)s).error);
+202          else if (s == OnComplete.Instance) // We are always able to handle OnError, obeying rule 2.9
+203            handleOnComplete();
+204        }
+205      } finally {
+206        on.set(false); // establishes a happens-before relationship with the beginning of the next run
+207        if(!inboundSignals.isEmpty()) // If we still have signals to process
+208          tryScheduleToExecute(); // Then we try to schedule ourselves to execute again
+209      }
+210    }
+211  }
+212
+213  // What `signal` does is that it sends signals to the `Subscription` asynchronously
+214  private void signal(final Signal signal) {
+215    if (inboundSignals.offer(signal)) // No need to null-check here as ConcurrentLinkedQueue does this for us
+216      tryScheduleToExecute(); // Then we try to schedule it for execution, if it isn't already
+217  }
+218
+219  // This method makes sure that this `Subscriber` is only executing on one Thread at a time
+220  private final void tryScheduleToExecute() {
+221    if(on.compareAndSet(false, true)) {
+222      try {
+223        executor.execute(this);
+224      } catch(Throwable t) { // If we can't run on the `Executor`, we need to fail gracefully and not violate rule 2.13
+225        if (!done) {
+226          try {
+227            done(); // First of all, this failure is not recoverable, so we need to cancel our subscription
+228          } finally {
+229            inboundSignals.clear(); // We're not going to need these anymore
+230            // This subscription is cancelled by now, but letting the Subscriber become schedulable again means
+231            // that we can drain the inboundSignals queue if anything arrives after clearing
+232            on.set(false);
+233          }
+234        }
+235      }
+236    }
+237  }
+238}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html new file mode 100644 index 0000000..51e0892 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.html @@ -0,0 +1,95 @@ + + + +Source code + + + +
+
001package org.reactivestreams.example.unicast;
+002
+003import java.util.Iterator;
+004import java.util.concurrent.Executor;
+005
+006import org.reactivestreams.Subscription;
+007import org.reactivestreams.Subscriber;
+008import org.reactivestreams.Publisher;
+009
+010public class InfiniteIncrementNumberPublisher extends AsyncIterablePublisher<Integer> {
+011    public InfiniteIncrementNumberPublisher(final Executor executor) {
+012        super(new Iterable<Integer>() {
+013          @Override public Iterator<Integer> iterator() {
+014            return new Iterator<Integer>() {
+015              private int at = 0;
+016              @Override public boolean hasNext() { return true; }
+017              @Override public Integer next() { return at++; } // Wraps around on overflow
+018              @Override public void remove() { throw new UnsupportedOperationException(); }
+019            };
+020          }
+021        }, executor);
+022    }
+023}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/NumberIterablePublisher.html b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/NumberIterablePublisher.html new file mode 100644 index 0000000..f81afe4 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/NumberIterablePublisher.html @@ -0,0 +1,99 @@ + + + +Source code + + + +
+
001package org.reactivestreams.example.unicast;
+002
+003import java.util.Collections;
+004import java.util.Iterator;
+005import java.util.concurrent.Executor;
+006import org.reactivestreams.Subscription;
+007import org.reactivestreams.Subscriber;
+008import org.reactivestreams.Publisher;
+009
+010public class NumberIterablePublisher extends AsyncIterablePublisher<Integer> {
+011    public NumberIterablePublisher(final int from, final int to, final Executor executor) {
+012        super(new Iterable<Integer>() {
+013          { if(from > to) throw new IllegalArgumentException("from must be equal or greater than to!"); }
+014          @Override public Iterator<Integer> iterator() {
+015            return new Iterator<Integer>() {
+016              private int at = from;
+017              @Override public boolean hasNext() { return at < to; }
+018              @Override public Integer next() {
+019                if (!hasNext()) return Collections.<Integer>emptyList().iterator().next();
+020                else return at++;
+021              }
+022              @Override public void remove() { throw new UnsupportedOperationException(); }
+023            };
+024          }
+025        }, executor);
+026    }
+027}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/SyncSubscriber.html b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/SyncSubscriber.html new file mode 100644 index 0000000..17f8df7 --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/src-html/org/reactivestreams/example/unicast/SyncSubscriber.html @@ -0,0 +1,183 @@ + + + +Source code + + + +
+
001package org.reactivestreams.example.unicast;
+002
+003import org.reactivestreams.Subscriber;
+004import org.reactivestreams.Subscription;
+005
+006/**
+007 * SyncSubscriber is an implementation of Reactive Streams `Subscriber`,
+008 * it runs synchronously (on the Publisher's thread) and requests one element
+009 * at a time and invokes a user-defined method to process each element.
+010 *
+011 * NOTE: The code below uses a lot of try-catches to show the reader where exceptions can be expected, and where they are forbidden.
+012 */
+013public abstract class SyncSubscriber<T> implements Subscriber<T> {
+014  private Subscription subscription; // Obeying rule 3.1, we make this private!
+015  private boolean done = false;
+016
+017  @Override public void onSubscribe(final Subscription s) {
+018    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Subscription` is `null`
+019    if (s == null) throw null;
+020
+021    if (subscription != null) { // If someone has made a mistake and added this Subscriber multiple times, let's handle it gracefully
+022      try {
+023        s.cancel(); // Cancel the additional subscription
+024      } catch(final Throwable t) {
+025        //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+026        (new IllegalStateException(s + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+027      }
+028    } else {
+029      // We have to assign it locally before we use it, if we want to be a synchronous `Subscriber`
+030      // Because according to rule 3.10, the Subscription is allowed to call `onNext` synchronously from within `request`
+031      subscription = s;
+032      try {
+033        // If we want elements, according to rule 2.1 we need to call `request`
+034        // And, according to rule 3.2 we are allowed to call this synchronously from within the `onSubscribe` method
+035        s.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+036      } catch(final Throwable t) {
+037        // Subscription.request is not allowed to throw according to rule 3.16
+038        (new IllegalStateException(s + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+039      }
+040    }
+041  }
+042
+043  @Override public void onNext(final T element) {
+044    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+045      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onNext prior to onSubscribe.")).printStackTrace(System.err);
+046    } else {
+047      // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `element` is `null`
+048      if (element == null) throw null;
+049
+050      if (!done) { // If we aren't already done
+051        try {
+052          if (foreach(element)) {
+053            try {
+054              subscription.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+055            } catch (final Throwable t) {
+056              // Subscription.request is not allowed to throw according to rule 3.16
+057              (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+058            }
+059          } else {
+060            done();
+061          }
+062        } catch (final Throwable t) {
+063          done();
+064          try {
+065            onError(t);
+066          } catch (final Throwable t2) {
+067            //Subscriber.onError is not allowed to throw an exception, according to rule 2.13
+068            (new IllegalStateException(this + " violated the Reactive Streams rule 2.13 by throwing an exception from onError.", t2)).printStackTrace(System.err);
+069          }
+070        }
+071      }
+072    }
+073  }
+074
+075  // Showcases a convenience method to idempotently marking the Subscriber as "done", so we don't want to process more elements
+076  // herefor we also need to cancel our `Subscription`.
+077  private void done() {
+078    //On this line we could add a guard against `!done`, but since rule 3.7 says that `Subscription.cancel()` is idempotent, we don't need to.
+079    done = true; // If we `foreach` throws an exception, let's consider ourselves done (not accepting more elements)
+080    try {
+081      subscription.cancel(); // Cancel the subscription
+082    } catch(final Throwable t) {
+083      //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+084      (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+085    }
+086  }
+087
+088  // This method is left as an exercise to the reader/extension point
+089  // Returns whether more elements are desired or not, and if no more elements are desired
+090  protected abstract boolean foreach(final T element);
+091
+092  @Override public void onError(final Throwable t) {
+093    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+094      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onError prior to onSubscribe.")).printStackTrace(System.err);
+095    } else {
+096      // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Throwable` is `null`
+097      if (t == null) throw null;
+098      // Here we are not allowed to call any methods on the `Subscription` or the `Publisher`, as per rule 2.3
+099      // And anyway, the `Subscription` is considered to be cancelled if this method gets called, as per rule 2.4
+100    }
+101  }
+102
+103  @Override public void onComplete() {
+104    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+105      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onComplete prior to onSubscribe.")).printStackTrace(System.err);
+106    } else {
+107      // Here we are not allowed to call any methods on the `Subscription` or the `Publisher`, as per rule 2.3
+108      // And anyway, the `Subscription` is considered to be cancelled if this method gets called, as per rule 2.4
+109    }
+110  }
+111}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-examples-1.0.0-javadoc/stylesheet.css b/reactive-streams-examples-1.0.0-javadoc/stylesheet.css new file mode 100644 index 0000000..cebb4fd --- /dev/null +++ b/reactive-streams-examples-1.0.0-javadoc/stylesheet.css @@ -0,0 +1,574 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + +@import url('resources/fonts/dejavu.css'); + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D7A97; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D7A97; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D7A97; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; + width:100%; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} diff --git a/reactive-streams-tck-1.0.0-javadoc/allclasses-frame.html b/reactive-streams-tck-1.0.0-javadoc/allclasses-frame.html new file mode 100644 index 0000000..25aa325 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/allclasses-frame.html @@ -0,0 +1,50 @@ + + + + + + +All Classes (reactive-streams-tck 1.0.0 API) + + + + +

All Classes

+
+ +
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/allclasses-noframe.html b/reactive-streams-tck-1.0.0-javadoc/allclasses-noframe.html new file mode 100644 index 0000000..66c4ff9 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/allclasses-noframe.html @@ -0,0 +1,50 @@ + + + + + + +All Classes (reactive-streams-tck 1.0.0 API) + + + + +

All Classes

+
+ +
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/constant-values.html b/reactive-streams-tck-1.0.0-javadoc/constant-values.html new file mode 100644 index 0000000..f2479a6 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/constant-values.html @@ -0,0 +1,177 @@ + + + + + + +Constant Field Values (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Constant Field Values

+

Contents

+ +
+
+ + +

org.reactivestreams.*

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/deprecated-list.html b/reactive-streams-tck-1.0.0-javadoc/deprecated-list.html new file mode 100644 index 0000000..95ec91f --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/deprecated-list.html @@ -0,0 +1,122 @@ + + + + + + +Deprecated List (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Deprecated API

+

Contents

+
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/help-doc.html b/reactive-streams-tck-1.0.0-javadoc/help-doc.html new file mode 100644 index 0000000..3e19ac5 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/help-doc.html @@ -0,0 +1,223 @@ + + + + + + +API Help (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

How This API Document Is Organized

+
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
+
+
+ +This help file applies to API documentation generated using the standard doclet.
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/index-all.html b/reactive-streams-tck-1.0.0-javadoc/index-all.html new file mode 100644 index 0000000..d483dc5 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/index-all.html @@ -0,0 +1,1506 @@ + + + + + + +Index (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
A B C D E F G H I L M N O P R S T U V W  + + +

A

+
+
activePublisherTest(long, boolean, PublisherVerification.PublisherTestRun<T>) - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Test for feature that SHOULD/MUST be implemented, using a live publisher.
+
+
add(T) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
apply(In) - Method in interface org.reactivestreams.tck.support.Function
+
 
+
assertClosed(String) - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
assertOpen(String) - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
+ + + +

B

+
+
BlackboxProbe(TestEnvironment, TestEnvironment.Promise<Subscriber<? super T>>) - Constructor for class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
BlackboxSubscriberProxy(TestEnvironment, Subscriber<T>) - Constructor for class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy
+
 
+
blackboxSubscriberTest(SubscriberBlackboxVerification<T>.BlackboxTestStageTestRun) - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
blackboxSubscriberWithoutSetupTest(SubscriberBlackboxVerification<T>.BlackboxTestStageTestRun) - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
BlackboxTestStage(TestEnvironment) - Constructor for class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
BlackboxTestStage(TestEnvironment, boolean) - Constructor for class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
BlackholeSubscriberWithSubscriptionSupport(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport
+
 
+
boundedDepthOfOnNextAndRequestRecursion() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a + Subscription actually solves the "unbounded recursion" problem by not allowing the number of + recursive calls to exceed the number returned by this method.
+
+
boundedDepthOfOnNextAndRequestRecursion() - Method in class org.reactivestreams.tck.PublisherVerification
+
+
In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a + Subscription actually solves the "unbounded recursion" problem by not allowing the number of + recursive calls to exceed the number returned by this method.
+
+
+ + + +

C

+
+
cancel() - Method in class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
cancelled - Variable in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
clearAsyncErrors() - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
close() - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
complete(T) - Method in class org.reactivestreams.tck.TestEnvironment.Promise
+
+
Allows using expectCompletion to await for completion of the value and complete it _then_
+
+
complete() - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
completed(TestEnvironment, T) - Static method in class org.reactivestreams.tck.TestEnvironment.Promise
+
 
+
completeImmediatly(T) - Method in class org.reactivestreams.tck.TestEnvironment.Promise
+
+
Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+
+
createBlackboxSubscriberProxy(TestEnvironment, Subscriber<T>) - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
createElement(int) - Method in class org.reactivestreams.tck.WithHelperPublisher
+
+
Implement this method to match your expected element type.
+
+
createFailedPublisher() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+
+
createFailedPublisher() - Method in class org.reactivestreams.tck.PublisherVerification
+
+
By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+
+
createHelperPublisher(long) - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
createHelperPublisher(long) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
createHelperPublisher(long) - Method in class org.reactivestreams.tck.WithHelperPublisher
+
+
Helper method required for creating the Publisher to which the tested Subscriber will be subscribed and tested against.
+
+
createIdentityProcessor(int) - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
This is the main method you must implement in your test incarnation.
+
+
createPublisher(long) - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
createPublisher(long) - Method in class org.reactivestreams.tck.PublisherVerification
+
+
This is the main method you must implement in your test incarnation.
+
+
createSubscriber(SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T>) - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
createSubscriber() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
+
This is the main method you must implement in your test incarnation.
+
+
createSubscriber(SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T>) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
+
This is the main method you must implement in your test incarnation.
+
+
createWhiteboxSubscriberProbe(TestEnvironment) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
+ + + +

D

+
+
debug(String) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
If TestEnvironment#printlnDebug is true, print debug message to std out.
+
+
defaultTimeoutMillis() - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
dropAsyncError() - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
+ + + +

E

+
+
elements - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
empty() - Static method in class org.reactivestreams.tck.support.Optional
+
 
+
env - Variable in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
env - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
env - Variable in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
env - Variable in class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
envDefaultTimeoutMillis() - Static method in class org.reactivestreams.tck.TestEnvironment
+
+
Tries to parse the env variable DEFAULT_TIMEOUT_MILLIS as long and returns the value if present OR its default value.
+
+
envPublisherReferenceGCTimeoutMillis() - Static method in class org.reactivestreams.tck.PublisherVerification
+
+
Tries to parse the env variable PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS as long and returns the value if present, + OR its default value (PublisherVerification.DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS).
+
+
error - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectCancelling() - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectCancelling(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectClose(String) - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
expectClose(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
expectCompletion() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectCompletion(long) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectCompletion(long, String) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectCompletion() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectCompletion(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectCompletion(String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectCompletion(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectCompletion(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Promise
+
 
+
expectCompletion(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
expectError(Throwable) - Method in class org.reactivestreams.tck.IdentityProcessorVerification.ManualSubscriberWithErrorCollection
+
 
+
expectError(Throwable, long) - Method in class org.reactivestreams.tck.IdentityProcessorVerification.ManualSubscriberWithErrorCollection
+
 
+
expectError(Class<E>) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectError(Class<E>, long) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectError(Throwable) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectError(Throwable, long) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectError(Class<E>) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectError(Class<E>, long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectError(Class<E>, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectError(Class<E>, long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectError(Class<E>, long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
expectErrorWithMessage(Class<E>, String) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectErrorWithMessage(Class<E>, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectErrorWithMessage(Class<E>, String, long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectExactRequest(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectExactRequest(long, long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectNext() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectNext(T) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectNext(T, long) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectNext(T) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectNext(T, long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectNextElement(TestEnvironment.ManualSubscriber<T>, T) - Method in class org.reactivestreams.tck.IdentityProcessorVerification.TestSetup
+
 
+
expectNone() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectNone(long) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
expectNone() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectNone(String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectNone(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectNone(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
expectNone(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
expectNoRequest() - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectNoRequest(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectRequest() - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
expectRequest(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
+ + + +

F

+
+
findCallerMethodInStackTrace(String) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
Looks for given method method in stack trace.
+
+
flop(String) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+
+
flop(Throwable, String) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+
+
flop(Throwable) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+
+
flopAndFail(String) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+
+
Function<In,Out> - Interface in org.reactivestreams.tck.support
+
 
+
+ + + +

G

+
+
get() - Method in class org.reactivestreams.tck.support.Optional
+
 
+
get() - Method in class org.reactivestreams.tck.support.Optional.Some
+
 
+
+ + + +

H

+
+
HelperPublisher<T> - Class in org.reactivestreams.tck.support
+
 
+
HelperPublisher(int, int, Function<Integer, T>, Executor) - Constructor for class org.reactivestreams.tck.support.HelperPublisher
+
 
+
+ + + +

I

+
+
IdentityProcessorVerification<T> - Class in org.reactivestreams.tck
+
 
+
IdentityProcessorVerification(TestEnvironment) - Constructor for class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Test class must specify the expected time it takes for the publisher to + shut itself down when the the last downstream Subscription is cancelled.
+
+
IdentityProcessorVerification(TestEnvironment, long) - Constructor for class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Test class must specify the expected time it takes for the publisher to + shut itself down when the the last downstream Subscription is cancelled.
+
+
IdentityProcessorVerification(TestEnvironment, long, int) - Constructor for class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Test class must specify the expected time it takes for the publisher to + shut itself down when the the last downstream Subscription is cancelled.
+
+
IdentityProcessorVerification.ManualSubscriberWithErrorCollection<A> - Class in org.reactivestreams.tck
+
 
+
IdentityProcessorVerification.TestSetup - Class in org.reactivestreams.tck
+
 
+
InfiniteHelperPublisher<T> - Class in org.reactivestreams.tck.support
+
 
+
InfiniteHelperPublisher(Function<Integer, T>, Executor) - Constructor for class org.reactivestreams.tck.support.InfiniteHelperPublisher
+
 
+
isClosed() - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
isCompleted() - Method in class org.reactivestreams.tck.TestEnvironment.Promise
+
 
+
isDefined() - Method in class org.reactivestreams.tck.support.Optional
+
 
+
isEmpty() - Method in class org.reactivestreams.tck.support.Optional
+
 
+
isEmpty() - Method in class org.reactivestreams.tck.support.Optional.Some
+
 
+
isNonFatal(Throwable) - Static method in class org.reactivestreams.tck.support.NonFatal
+
+
Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
+
+
+ + + +

L

+
+
lastT - Variable in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
lastT - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
Latch(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
+ + + +

M

+
+
ManualPublisher(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
ManualSubscriber(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
ManualSubscriberWithErrorCollection(TestEnvironment) - Constructor for class org.reactivestreams.tck.IdentityProcessorVerification.ManualSubscriberWithErrorCollection
+
 
+
ManualSubscriberWithSubscriptionSupport(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport
+
 
+
maxElementsFromPublisher() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Override and return lower value if your Publisher is only able to produce a known number of elements.
+
+
maxElementsFromPublisher() - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Override and return lower value if your Publisher is only able to produce a known number of elements.
+
+
maxSupportedSubscribers() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Describes the tested implementation in terms of how many subscribers they can support.
+
+
mustImmediatelyPassOnOnErrorEventsReceivedFromItsUpstreamToItsDownstream() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
+ + + +

N

+
+
newBlackholeSubscriber(Publisher<T>) - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
newManualSubscriber(Publisher<T>) - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
newManualSubscriber(Publisher<T>, long) - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
newSubscriber() - Method in class org.reactivestreams.tck.IdentityProcessorVerification.TestSetup
+
 
+
next(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
nextElement(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport
+
 
+
nextElement() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElement(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElement(String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElement(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElementOrEndOfStream() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElementOrEndOfStream(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElementOrEndOfStream(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElements(long, long, String) - Method in class org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport
+
 
+
nextElements(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElements(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElements(long, long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextElements(long, long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
nextN(long, long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
nextOrEndOfStream(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.Receptacle
+
 
+
nextT() - Method in class org.reactivestreams.tck.IdentityProcessorVerification.TestSetup
+
 
+
nextT() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
nextT() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
NonFatal - Class in org.reactivestreams.tck.support
+
+
Copy of scala.control.util.NonFatal in order to not depend on scala-library
+
+
notVerified() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
notVerified(String) - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
notVerified() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
notVerified(String) - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
notVerified() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
notVerified() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
notVerified(String) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
+ + + +

O

+
+
of(T) - Static method in class org.reactivestreams.tck.support.Optional
+
 
+
onComplete() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy
+
 
+
onComplete() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
onComplete() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport
+
 
+
onComplete() - Method in class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
onError(Throwable) - Method in class org.reactivestreams.tck.IdentityProcessorVerification.ManualSubscriberWithErrorCollection
+
 
+
onError(Throwable) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy
+
 
+
onError(Throwable) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport
+
 
+
onError(Throwable) - Method in class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
onNext(T) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy
+
 
+
onNext(T) - Method in class org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport
+
 
+
onNext(T) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
onNext(T) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport
+
 
+
onNext(T) - Method in class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
onSubscribe(Subscription) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy
+
 
+
onSubscribe(Subscription) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport
+
 
+
onSubscribe(Subscription) - Method in class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
Optional<T> - Class in org.reactivestreams.tck.support
+
 
+
Optional.Some<T> - Class in org.reactivestreams.tck.support
+
 
+
optional_spec104_mustSignalOnErrorWhenFails() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
optional_spec104_mustSignalOnErrorWhenFails() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
optional_spec104_mustSignalOnErrorWhenFails() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
optional_spec111_maySupportMultiSubscribe() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
optional_spec111_maySupportMultiSubscribe() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
optional_spec111_maySupportMultiSubscribe() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
optionalActivePublisherTest(long, boolean, PublisherVerification.PublisherTestRun<T>) - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Test for feature that MAY be implemented.
+
+
optionalMultipleSubscribersTest(long, Function<Long, IdentityProcessorVerification<T>.TestSetup>) - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Test for feature that REQUIRES multiple subscribers to be supported by Publisher.
+
+
optionalSubscriberTestWithoutSetup(SubscriberWhiteboxVerification<T>.TestStageTestRun) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
+
Test for feature that MAY be implemented.
+
+
org.reactivestreams.tck - package org.reactivestreams.tck
+
 
+
org.reactivestreams.tck.support - package org.reactivestreams.tck.support
+
 
+
+ + + +

P

+
+
pendingDemand - Variable in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
potentiallyPendingTest(Publisher<T>, PublisherVerification.PublisherTestRun<T>) - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
potentiallyPendingTest(Publisher<T>, PublisherVerification.PublisherTestRun<T>, String) - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
probe - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
probe() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
Promise(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.Promise
+
 
+
pub - Variable in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
pub - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
publisherExecutorService() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
publisherExecutorService() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
publisherExecutorService() - Method in class org.reactivestreams.tck.WithHelperPublisher
+
+
ExecutorService to be used by the provided helper Publisher
+
+
publisherUnableToSignalOnComplete() - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Return this value from PublisherVerification.maxElementsFromPublisher() to mark that the given Publisher, + is not able to signal completion.
+
+
PublisherVerification<T> - Class in org.reactivestreams.tck
+
+
Provides tests for verifying Publisher specification rules.
+
+
PublisherVerification(TestEnvironment, long) - Constructor for class org.reactivestreams.tck.PublisherVerification
+
+
Constructs a new verification class using the given env and configuration.
+
+
PublisherVerification(TestEnvironment) - Constructor for class org.reactivestreams.tck.PublisherVerification
+
+
Constructs a new verification class using the given env and configuration.
+
+
PublisherVerification.PublisherTestRun<T> - Interface in org.reactivestreams.tck
+
 
+
PublisherVerificationRules - Interface in org.reactivestreams.tck.support
+
+
Internal TCK use only.
+
+
puppet - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxSubscriberProbe
+
 
+
puppet() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
+ + + +

R

+
+
registerOnComplete() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
registerOnComplete() - Method in interface org.reactivestreams.tck.SubscriberWhiteboxVerification.SubscriberProbe
+
+
Must be called by the test subscriber when it has received an `onComplete` event.
+
+
registerOnError(Throwable) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
registerOnError(Throwable) - Method in interface org.reactivestreams.tck.SubscriberWhiteboxVerification.SubscriberProbe
+
+
Must be called by the test subscriber when it has received an `onError` event.
+
+
registerOnNext(T) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
registerOnNext(T) - Method in interface org.reactivestreams.tck.SubscriberWhiteboxVerification.SubscriberProbe
+
+
Must be called by the test subscriber when it has received an`onNext` event.
+
+
registerOnSubscribe(SubscriberWhiteboxVerification.SubscriberPuppet) - Method in interface org.reactivestreams.tck.SubscriberWhiteboxVerification.SubscriberPuppeteer
+
+
Must be called by the test subscriber when it has successfully registered a subscription + inside the `onSubscribe` method.
+
+
registerOnSubscribe(SubscriberWhiteboxVerification.SubscriberPuppet) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxSubscriberProbe
+
 
+
reOpen() - Method in class org.reactivestreams.tck.TestEnvironment.Latch
+
 
+
request(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestEndOfStream() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestEndOfStream(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestEndOfStream(String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestEndOfStream(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElement() - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElement(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElement(String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElement(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElementOrEndOfStream(String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElementOrEndOfStream(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElementOrEndOfStream(long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElements(long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElements(long, long) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requestNextElements(long, long, String) - Method in class org.reactivestreams.tck.TestEnvironment.ManualSubscriber
+
 
+
requests - Variable in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
required_createPublisher1MustProduceAStreamOfExactly1Element() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_createPublisher1MustProduceAStreamOfExactly1Element() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_createPublisher1MustProduceAStreamOfExactly1Element() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_createPublisher3MustProduceAStreamOfExactly3Elements() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_createPublisher3MustProduceAStreamOfExactly3Elements() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_createPublisher3MustProduceAStreamOfExactly3Elements() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_exerciseWhiteboxHappyPath() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_exerciseWhiteboxHappyPath() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_exerciseWhiteboxHappyPath() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec102_maySignalLessThanRequestedAndTerminateSubscription() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec102_maySignalLessThanRequestedAndTerminateSubscription() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec102_maySignalLessThanRequestedAndTerminateSubscription() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec109_mustIssueOnSubscribeForNonNullSubscriber() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec109_mustIssueOnSubscribeForNonNullSubscriber() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec109_mustIssueOnSubscribeForNonNullSubscriber() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec109_subscribeThrowNPEOnNullSubscriber() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec109_subscribeThrowNPEOnNullSubscriber() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec109_subscribeThrowNPEOnNullSubscriber() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec201_mustSignalDemandViaSubscriptionRequest() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec201_mustSignalDemandViaSubscriptionRequest() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec201_mustSignalDemandViaSubscriptionRequest() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec303_mustNotAllowUnboundedRecursion() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec303_mustNotAllowUnboundedRecursion() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec303_mustNotAllowUnboundedRecursion() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec309_requestZeroMustSignalIllegalArgumentException() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec309_requestZeroMustSignalIllegalArgumentException() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec309_requestZeroMustSignalIllegalArgumentException() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_validate_boundedDepthOfOnNextAndRequestRecursion() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_validate_boundedDepthOfOnNextAndRequestRecursion() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_validate_boundedDepthOfOnNextAndRequestRecursion() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
required_validate_maxElementsFromPublisher() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
required_validate_maxElementsFromPublisher() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
required_validate_maxElementsFromPublisher() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
run(Publisher<T>) - Method in interface org.reactivestreams.tck.PublisherVerification.PublisherTestRun
+
 
+
+ + + +

S

+
+
sendCompletion() - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
sendError(Throwable) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
sendNext(T) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
sendNextTFromUpstream() - Method in class org.reactivestreams.tck.IdentityProcessorVerification.TestSetup
+
 
+
setUp() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
setUp() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
setUp() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
setUp() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
shutdownPublisherExecutorService() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
shutdownPublisherExecutorService() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
signalCancel() - Method in interface org.reactivestreams.tck.SubscriberWhiteboxVerification.SubscriberPuppet
+
 
+
signalNext() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
signalNext() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE - Static variable in class org.reactivestreams.tck.PublisherVerification
+
 
+
SKIPPING_OPTIONAL_TEST_FAILED - Static variable in class org.reactivestreams.tck.PublisherVerification
+
 
+
skipStochasticTests() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
+
Override and return true in order to skip executing tests marked as Stochastic.
+
+
skipStochasticTests() - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Override and return true in order to skip executing tests marked as Stochastic.
+
+
startPublisherExecutorService() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
startPublisherExecutorService() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
stochastic_spec103_mustSignalOnMethodsSequentially() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
stochastic_spec103_mustSignalOnMethodsSequentially() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
stochastic_spec103_mustSignalOnMethodsSequentially() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
stochasticTest(int, Function<Integer, Void>) - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Executes a given test body n times.
+
+
sub() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
sub() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
sub() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
subProxy() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
+
Proxy for the SubscriberBlackboxVerification.BlackboxTestStage.sub() Subscriber, providing certain assertions on methods being called on the Subscriber.
+
+
subscribe(Subscriber<? super T>) - Method in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
subscribe(Publisher<T>, TestEnvironment.TestSubscriber<T>) - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
subscribe(Publisher<T>, TestEnvironment.TestSubscriber<T>, long) - Method in class org.reactivestreams.tck.TestEnvironment
+
 
+
subscriber - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxProbe
+
 
+
subscriber - Variable in class org.reactivestreams.tck.TestEnvironment.ManualPublisher
+
 
+
SubscriberBlackboxVerification<T> - Class in org.reactivestreams.tck
+
+
Provides tests for verifying Subscriber and Subscription + specification rules, without any modifications to the tested implementation (also known as "Black Box" testing).
+
+
SubscriberBlackboxVerification(TestEnvironment) - Constructor for class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
SubscriberBlackboxVerification.BlackboxTestStage - Class in org.reactivestreams.tck
+
 
+
SubscriberBlackboxVerificationRules - Interface in org.reactivestreams.tck.support
+
+
Internal TCK use only.
+
+
SubscriberBufferOverflowException - Exception in org.reactivestreams.tck.support
+
 
+
SubscriberBufferOverflowException() - Constructor for exception org.reactivestreams.tck.support.SubscriberBufferOverflowException
+
 
+
SubscriberBufferOverflowException(String) - Constructor for exception org.reactivestreams.tck.support.SubscriberBufferOverflowException
+
 
+
SubscriberBufferOverflowException(String, Throwable) - Constructor for exception org.reactivestreams.tck.support.SubscriberBufferOverflowException
+
 
+
SubscriberBufferOverflowException(Throwable) - Constructor for exception org.reactivestreams.tck.support.SubscriberBufferOverflowException
+
 
+
subscriberTest(SubscriberWhiteboxVerification<T>.TestStageTestRun) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
+
Prepares subscriber and publisher pair (by subscribing the first to the latter), + and then hands over the tests SubscriberWhiteboxVerification.WhiteboxTestStage over to the test.
+
+
subscriberTestWithoutSetup(SubscriberWhiteboxVerification<T>.TestStageTestRun) - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
+ +
+
SubscriberWhiteboxVerification<T> - Class in org.reactivestreams.tck
+
+
Provides tests for verifying Subscriber and Subscription specification rules.
+
+
SubscriberWhiteboxVerification(TestEnvironment) - Constructor for class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
SubscriberWhiteboxVerification.BlackboxProbe<T> - Class in org.reactivestreams.tck
+
 
+
SubscriberWhiteboxVerification.BlackboxSubscriberProxy<T> - Class in org.reactivestreams.tck
+
+
This class is intented to be used as Subscriber decorator and should be used in pub.subscriber(...) calls, + in order to allow intercepting calls on the underlying Subscriber.
+
+
SubscriberWhiteboxVerification.SubscriberProbe<T> - Interface in org.reactivestreams.tck
+
 
+
SubscriberWhiteboxVerification.SubscriberPuppet - Interface in org.reactivestreams.tck
+
 
+
SubscriberWhiteboxVerification.SubscriberPuppeteer - Interface in org.reactivestreams.tck
+
 
+
SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T> - Class in org.reactivestreams.tck
+
 
+
SubscriberWhiteboxVerification.WhiteboxTestStage - Class in org.reactivestreams.tck
+
 
+
SubscriberWhiteboxVerificationRules - Interface in org.reactivestreams.tck.support
+
+
Internal TCK use only.
+
+
+ + + +

T

+
+
tees - Variable in class org.reactivestreams.tck.SubscriberBlackboxVerification.BlackboxTestStage
+
 
+
tees - Variable in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
TEST_BUFFER_SIZE - Static variable in class org.reactivestreams.tck.TestEnvironment
+
 
+
TestEnvironment - Class in org.reactivestreams.tck
+
 
+
TestEnvironment(long, boolean) - Constructor for class org.reactivestreams.tck.TestEnvironment
+
+
Tests must specify the timeout for expected outcome of asynchronous + interactions.
+
+
TestEnvironment(long) - Constructor for class org.reactivestreams.tck.TestEnvironment
+
+
Tests must specify the timeout for expected outcome of asynchronous + interactions.
+
+
TestEnvironment(boolean) - Constructor for class org.reactivestreams.tck.TestEnvironment
+
+
Tests must specify the timeout for expected outcome of asynchronous + interactions.
+
+
TestEnvironment() - Constructor for class org.reactivestreams.tck.TestEnvironment
+
+
Tests must specify the timeout for expected outcome of asynchronous + interactions.
+
+
TestEnvironment.BlackholeSubscriberWithSubscriptionSupport<T> - Class in org.reactivestreams.tck
+
+
Similar to TestEnvironment.ManualSubscriberWithSubscriptionSupport + but does not accumulate values signalled via onNext, thus it can not be used to assert + values signalled to this subscriber.
+
+
TestEnvironment.Latch - Class in org.reactivestreams.tck
+
+
Like a CountDownLatch, but resettable and with some convenience methods
+
+
TestEnvironment.ManualPublisher<T> - Class in org.reactivestreams.tck
+
 
+
TestEnvironment.ManualSubscriber<T> - Class in org.reactivestreams.tck
+
+
Subscriber implementation which can be steered by test code and asserted on.
+
+
TestEnvironment.ManualSubscriberWithSubscriptionSupport<T> - Class in org.reactivestreams.tck
+
 
+
TestEnvironment.Promise<T> - Class in org.reactivestreams.tck
+
 
+
TestEnvironment.Receptacle<T> - Class in org.reactivestreams.tck
+
 
+
TestEnvironment.TestSubscriber<T> - Class in org.reactivestreams.tck
+
 
+
TestException - Exception in org.reactivestreams.tck.support
+
+
Exception used by the TCK to signal failures.
+
+
TestException() - Constructor for exception org.reactivestreams.tck.support.TestException
+
 
+
TestSetup(TestEnvironment, int) - Constructor for class org.reactivestreams.tck.IdentityProcessorVerification.TestSetup
+
 
+
TestSubscriber(TestEnvironment) - Constructor for class org.reactivestreams.tck.TestEnvironment.TestSubscriber
+
 
+
toString() - Method in class org.reactivestreams.tck.support.Optional.Some
+
 
+
toString() - Method in class org.reactivestreams.tck.support.Optional
+
 
+
triggerRequest(Subscriber<? super T>) - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
+
Override this method if the Subscriber implementation you are verifying + needs an external signal before it signals demand to its Publisher.
+
+
triggerRequest(long) - Method in interface org.reactivestreams.tck.SubscriberWhiteboxVerification.SubscriberPuppet
+
 
+
+ + + +

U

+
+
untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec109_subscribeShouldNotThrowNonFatalThrowable() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec109_subscribeShouldNotThrowNonFatalThrowable() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec109_subscribeShouldNotThrowNonFatalThrowable() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec202_blackbox_shouldAsynchronouslyDispatch() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec202_blackbox_shouldAsynchronouslyDispatch() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec202_shouldAsynchronouslyDispatch() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec202_shouldAsynchronouslyDispatch() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec202_shouldAsynchronouslyDispatch() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec213_blackbox_failingOnSignalInvocation() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec213_blackbox_failingOnSignalInvocation() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec213_failingOnSignalInvocation() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec213_failingOnSignalInvocation() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec213_failingOnSignalInvocation() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec301_mustNotBeCalledOutsideSubscriberContext() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec301_mustNotBeCalledOutsideSubscriberContext() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec301_mustNotBeCalledOutsideSubscriberContext() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec304_requestShouldNotPerformHeavyComputations() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec304_requestShouldNotPerformHeavyComputations() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec304_requestShouldNotPerformHeavyComputations() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() - Method in class org.reactivestreams.tck.PublisherVerification
+
 
+
untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() - Method in interface org.reactivestreams.tck.support.PublisherVerificationRules
+
 
+
untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() - Method in class org.reactivestreams.tck.SubscriberBlackboxVerification
+
 
+
untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() - Method in interface org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules
+
 
+
untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() - Method in class org.reactivestreams.tck.IdentityProcessorVerification
+
 
+
untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification
+
 
+
untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() - Method in interface org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules
+
 
+
+ + + +

V

+
+
value() - Method in class org.reactivestreams.tck.TestEnvironment.Promise
+
 
+
verifyNoAsyncErrors() - Method in class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
verifyNoAsyncErrors() - Method in class org.reactivestreams.tck.TestEnvironment
+
+
Waits for TestEnvironment.defaultTimeoutMillis() and then verifies that no asynchronous errors + were signalled pior to, or during that time (by calling flop()).
+
+
verifyNoAsyncErrors(long) - Method in class org.reactivestreams.tck.TestEnvironment
+
+
This version of verifyNoAsyncErrors should be used when errors still could be signalled + asynchronously during TestEnvironment.defaultTimeoutMillis() time.
+
+
verifyNoAsyncErrorsNoDelay() - Method in class org.reactivestreams.tck.TestEnvironment
+
+
Verifies that no asynchronous errors were signalled pior to calling this method (by calling flop()).
+
+
+ + + +

W

+
+
whenHasErrorPublisherTest(PublisherVerification.PublisherTestRun<T>) - Method in class org.reactivestreams.tck.PublisherVerification
+
+
Additional test for Publisher in error state
+
+
WhiteboxSubscriberProbe(TestEnvironment, TestEnvironment.Promise<Subscriber<? super T>>) - Constructor for class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxSubscriberProbe
+
 
+
WhiteboxTestStage(TestEnvironment) - Constructor for class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
WhiteboxTestStage(TestEnvironment, boolean) - Constructor for class org.reactivestreams.tck.SubscriberWhiteboxVerification.WhiteboxTestStage
+
 
+
WithHelperPublisher<T> - Class in org.reactivestreams.tck
+
+
Type which is able to create elements based on a seed id value.
+
+
WithHelperPublisher() - Constructor for class org.reactivestreams.tck.WithHelperPublisher
+
 
+
+A B C D E F G H I L M N O P R S T U V W 
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/index.html b/reactive-streams-tck-1.0.0-javadoc/index.html new file mode 100644 index 0000000..94af1c0 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/index.html @@ -0,0 +1,75 @@ + + + + + + +reactive-streams-tck 1.0.0 API + + + + + + + + + +<noscript> +<div>JavaScript is disabled on your browser.</div> +</noscript> +<h2>Frame Alert</h2> +<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="overview-summary.html">Non-frame version</a>.</p> + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html new file mode 100644 index 0000000..f608300 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html @@ -0,0 +1,372 @@ + + + + + + +IdentityProcessorVerification.ManualSubscriberWithErrorCollection (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class IdentityProcessorVerification.ManualSubscriberWithErrorCollection<A>

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html new file mode 100644 index 0000000..b70d670 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html @@ -0,0 +1,374 @@ + + + + + + +IdentityProcessorVerification.TestSetup (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class IdentityProcessorVerification.TestSetup

+
+
+ +
+ +
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        TestSetup

        +
        public TestSetup(TestEnvironment env,
        +                 int testBufferSize)
        +          throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      +
    • +
    + + +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.html new file mode 100644 index 0000000..cb87a67 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/IdentityProcessorVerification.html @@ -0,0 +1,1888 @@ + + + + + + +IdentityProcessorVerification (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class IdentityProcessorVerification<T>

+
+
+ + +
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html new file mode 100644 index 0000000..439c9bb --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html @@ -0,0 +1,228 @@ + + + + + + +PublisherVerification.PublisherTestRun (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Interface PublisherVerification.PublisherTestRun<T>

+
+
+
+ +
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        run

        +
        void run(org.reactivestreams.Publisher<T> pub)
        +  throws java.lang.Throwable
        +
        +
        Throws:
        +
        java.lang.Throwable
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.html new file mode 100644 index 0000000..befb950 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/PublisherVerification.html @@ -0,0 +1,1426 @@ + + + + + + +PublisherVerification (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class PublisherVerification<T>

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html new file mode 100644 index 0000000..c517fbc --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html @@ -0,0 +1,462 @@ + + + + + + +SubscriberBlackboxVerification.BlackboxTestStage (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberBlackboxVerification.BlackboxTestStage

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.html new file mode 100644 index 0000000..dc98524 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberBlackboxVerification.html @@ -0,0 +1,992 @@ + + + + + + +SubscriberBlackboxVerification (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberBlackboxVerification<T>

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    SubscriberBlackboxVerificationRules
    +
    +
    +
    +
    public abstract class SubscriberBlackboxVerification<T>
    +extends WithHelperPublisher<T>
    +implements SubscriberBlackboxVerificationRules
    +
    Provides tests for verifying Subscriber and Subscription + specification rules, without any modifications to the tested implementation (also known as "Black Box" testing). + + This verification is NOT able to check many of the rules of the spec, and if you want more + verification of your implementation you'll have to implement org.reactivestreams.tck.SubscriberWhiteboxVerification + instead.
    +
    +
    See Also:
    +
    Subscriber, +Subscription
    +
    +
  • +
+
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html new file mode 100644 index 0000000..fb2004f --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html @@ -0,0 +1,672 @@ + + + + + + +SubscriberWhiteboxVerification.BlackboxProbe (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberWhiteboxVerification.BlackboxProbe<T>

+
+
+ + +
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html new file mode 100644 index 0000000..3518826 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html @@ -0,0 +1,367 @@ + + + + + + +SubscriberWhiteboxVerification.BlackboxSubscriberProxy (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberWhiteboxVerification.BlackboxSubscriberProxy<T>

+
+
+ +
+ +
+
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        onSubscribe

        +
        public void onSubscribe(org.reactivestreams.Subscription s)
        +
        +
        Specified by:
        +
        onSubscribe in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + + + +
        +
      • +

        onNext

        +
        public void onNext(T t)
        +
        +
        Specified by:
        +
        onNext in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onError

        +
        public void onError(java.lang.Throwable cause)
        +
        +
        Specified by:
        +
        onError in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onComplete

        +
        public void onComplete()
        +
        +
        Specified by:
        +
        onComplete in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html new file mode 100644 index 0000000..39d0d63 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html @@ -0,0 +1,264 @@ + + + + + + +SubscriberWhiteboxVerification.SubscriberProbe (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Interface SubscriberWhiteboxVerification.SubscriberProbe<T>

+
+
+ +
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Abstract Methods 
      Modifier and TypeMethod and Description
      voidregisterOnComplete() +
      Must be called by the test subscriber when it has received an `onComplete` event.
      +
      voidregisterOnError(java.lang.Throwable cause) +
      Must be called by the test subscriber when it has received an `onError` event.
      +
      voidregisterOnNext(T element) +
      Must be called by the test subscriber when it has received an`onNext` event.
      +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + + + +
        +
      • +

        registerOnNext

        +
        void registerOnNext(T element)
        +
        Must be called by the test subscriber when it has received an`onNext` event.
        +
      • +
      + + + +
        +
      • +

        registerOnComplete

        +
        void registerOnComplete()
        +
        Must be called by the test subscriber when it has received an `onComplete` event.
        +
      • +
      + + + +
        +
      • +

        registerOnError

        +
        void registerOnError(java.lang.Throwable cause)
        +
        Must be called by the test subscriber when it has received an `onError` event.
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html new file mode 100644 index 0000000..e9e5eaf --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html @@ -0,0 +1,236 @@ + + + + + + +SubscriberWhiteboxVerification.SubscriberPuppet (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Interface SubscriberWhiteboxVerification.SubscriberPuppet

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html new file mode 100644 index 0000000..ac68d65 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html @@ -0,0 +1,232 @@ + + + + + + +SubscriberWhiteboxVerification.SubscriberPuppeteer (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Interface SubscriberWhiteboxVerification.SubscriberPuppeteer

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html new file mode 100644 index 0000000..02db757 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html @@ -0,0 +1,345 @@ + + + + + + +SubscriberWhiteboxVerification.WhiteboxSubscriberProbe (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T>

+
+
+ + +
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html new file mode 100644 index 0000000..c6a0be5 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html @@ -0,0 +1,496 @@ + + + + + + +SubscriberWhiteboxVerification.WhiteboxTestStage (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberWhiteboxVerification.WhiteboxTestStage

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.html new file mode 100644 index 0000000..4753c2e --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/SubscriberWhiteboxVerification.html @@ -0,0 +1,1050 @@ + + + + + + +SubscriberWhiteboxVerification (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class SubscriberWhiteboxVerification<T>

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html new file mode 100644 index 0000000..731e966 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html @@ -0,0 +1,385 @@ + + + + + + +TestEnvironment.BlackholeSubscriberWithSubscriptionSupport (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.BlackholeSubscriberWithSubscriptionSupport<T>

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Latch.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Latch.html new file mode 100644 index 0000000..3fec270 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Latch.html @@ -0,0 +1,364 @@ + + + + + + +TestEnvironment.Latch (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.Latch

+
+
+ +
+
    +
  • +
    +
    Enclosing class:
    +
    TestEnvironment
    +
    +
    +
    +
    public static class TestEnvironment.Latch
    +extends java.lang.Object
    +
    Like a CountDownLatch, but resettable and with some convenience methods
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      voidassertClosed(java.lang.String openErrorMsg) 
      voidassertOpen(java.lang.String closedErrorMsg) 
      voidclose() 
      voidexpectClose(long timeoutMillis, + java.lang.String notClosedErrorMsg) 
      voidexpectClose(java.lang.String notClosedErrorMsg) 
      booleanisClosed() 
      voidreOpen() 
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        reOpen

        +
        public void reOpen()
        +
      • +
      + + + +
        +
      • +

        isClosed

        +
        public boolean isClosed()
        +
      • +
      + + + +
        +
      • +

        close

        +
        public void close()
        +
      • +
      + + + +
        +
      • +

        assertClosed

        +
        public void assertClosed(java.lang.String openErrorMsg)
        +
      • +
      + + + +
        +
      • +

        assertOpen

        +
        public void assertOpen(java.lang.String closedErrorMsg)
        +
      • +
      + + + +
        +
      • +

        expectClose

        +
        public void expectClose(java.lang.String notClosedErrorMsg)
        +                 throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectClose

        +
        public void expectClose(long timeoutMillis,
        +                        java.lang.String notClosedErrorMsg)
        +                 throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html new file mode 100644 index 0000000..04aec77 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html @@ -0,0 +1,561 @@ + + + + + + +TestEnvironment.ManualPublisher (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.ManualPublisher<T>

+
+
+ +
+ +
+
+ +
+
+
    +
  • + + + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        subscribe

        +
        public void subscribe(org.reactivestreams.Subscriber<? super T> s)
        +
        +
        Specified by:
        +
        subscribe in interface org.reactivestreams.Publisher<T>
        +
        +
      • +
      + + + + + +
        +
      • +

        sendNext

        +
        public void sendNext(T element)
        +
      • +
      + + + + + + + +
        +
      • +

        sendError

        +
        public void sendError(java.lang.Throwable cause)
        +
      • +
      + + + +
        +
      • +

        expectRequest

        +
        public long expectRequest()
        +                   throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectRequest

        +
        public long expectRequest(long timeoutMillis)
        +                   throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectExactRequest

        +
        public void expectExactRequest(long expected)
        +                        throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectExactRequest

        +
        public void expectExactRequest(long expected,
        +                               long timeoutMillis)
        +                        throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectNoRequest

        +
        public void expectNoRequest()
        +                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectNoRequest

        +
        public void expectNoRequest(long timeoutMillis)
        +                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCancelling

        +
        public void expectCancelling()
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCancelling

        +
        public void expectCancelling(long timeoutMillis)
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html new file mode 100644 index 0000000..7d05bd8 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html @@ -0,0 +1,1135 @@ + + + + + + +TestEnvironment.ManualSubscriber (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.ManualSubscriber<T>

+
+
+ +
+ +
+
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + + + + + + + + + + + +
        +
      • +

        request

        +
        public void request(long elements)
        +
      • +
      + + + +
        +
      • +

        requestNextElement

        +
        public T requestNextElement()
        +                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElement

        +
        public T requestNextElement(long timeoutMillis)
        +                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElement

        +
        public T requestNextElement(java.lang.String errorMsg)
        +                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElement

        +
        public T requestNextElement(long timeoutMillis,
        +                            java.lang.String errorMsg)
        +                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElementOrEndOfStream

        +
        public Optional<TrequestNextElementOrEndOfStream(java.lang.String errorMsg)
        +                                            throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + + + + + +
        +
      • +

        requestNextElementOrEndOfStream

        +
        public Optional<TrequestNextElementOrEndOfStream(long timeoutMillis,
        +                                                   java.lang.String errorMsg)
        +                                            throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestEndOfStream

        +
        public void requestEndOfStream()
        +                        throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestEndOfStream

        +
        public void requestEndOfStream(long timeoutMillis)
        +                        throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestEndOfStream

        +
        public void requestEndOfStream(java.lang.String errorMsg)
        +                        throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestEndOfStream

        +
        public void requestEndOfStream(long timeoutMillis,
        +                               java.lang.String errorMsg)
        +                        throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElements

        +
        public java.util.List<TrequestNextElements(long elements)
        +                                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElements

        +
        public java.util.List<TrequestNextElements(long elements,
        +                                             long timeoutMillis)
        +                                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        requestNextElements

        +
        public java.util.List<TrequestNextElements(long elements,
        +                                             long timeoutMillis,
        +                                             java.lang.String errorMsg)
        +                                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElement

        +
        public T nextElement()
        +              throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElement

        +
        public T nextElement(long timeoutMillis)
        +              throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElement

        +
        public T nextElement(java.lang.String errorMsg)
        +              throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElement

        +
        public T nextElement(long timeoutMillis,
        +                     java.lang.String errorMsg)
        +              throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElementOrEndOfStream

        +
        public Optional<TnextElementOrEndOfStream()
        +                                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElementOrEndOfStream

        +
        public Optional<TnextElementOrEndOfStream(long timeoutMillis)
        +                                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElementOrEndOfStream

        +
        public Optional<TnextElementOrEndOfStream(long timeoutMillis,
        +                                            java.lang.String errorMsg)
        +                                     throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElements

        +
        public java.util.List<TnextElements(long elements)
        +                               throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElements

        +
        public java.util.List<TnextElements(long elements,
        +                                      java.lang.String errorMsg)
        +                               throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElements

        +
        public java.util.List<TnextElements(long elements,
        +                                      long timeoutMillis)
        +                               throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextElements

        +
        public java.util.List<TnextElements(long elements,
        +                                      long timeoutMillis,
        +                                      java.lang.String errorMsg)
        +                               throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + + + +
        +
      • +

        expectNext

        +
        public void expectNext(T expected)
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + + + +
        +
      • +

        expectNext

        +
        public void expectNext(T expected,
        +                       long timeoutMillis)
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCompletion

        +
        public void expectCompletion()
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCompletion

        +
        public void expectCompletion(long timeoutMillis)
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCompletion

        +
        public void expectCompletion(java.lang.String errorMsg)
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCompletion

        +
        public void expectCompletion(long timeoutMillis,
        +                             java.lang.String errorMsg)
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectErrorWithMessage

        +
        public <E extends java.lang.Throwable> void expectErrorWithMessage(java.lang.Class<E> expected,
        +                                                                   java.lang.String requiredMessagePart)
        +                                                            throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectErrorWithMessage

        +
        public <E extends java.lang.Throwable> void expectErrorWithMessage(java.lang.Class<E> expected,
        +                                                                   java.lang.String requiredMessagePart,
        +                                                                   long timeoutMillis)
        +                                                            throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectError

        +
        public <E extends java.lang.Throwable> E expectError(java.lang.Class<E> expected)
        +                                              throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectError

        +
        public <E extends java.lang.Throwable> E expectError(java.lang.Class<E> expected,
        +                                                     long timeoutMillis)
        +                                              throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectError

        +
        public <E extends java.lang.Throwable> E expectError(java.lang.Class<E> expected,
        +                                                     java.lang.String errorMsg)
        +                                              throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectError

        +
        public <E extends java.lang.Throwable> E expectError(java.lang.Class<E> expected,
        +                                                     long timeoutMillis,
        +                                                     java.lang.String errorMsg)
        +                                              throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectNone

        +
        public void expectNone()
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectNone

        +
        public void expectNone(java.lang.String errMsgPrefix)
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectNone

        +
        public void expectNone(long withinMillis)
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectNone

        +
        public void expectNone(long withinMillis,
        +                       java.lang.String errMsgPrefix)
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html new file mode 100644 index 0000000..de74095 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html @@ -0,0 +1,385 @@ + + + + + + +TestEnvironment.ManualSubscriberWithSubscriptionSupport (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.ManualSubscriberWithSubscriptionSupport<T>

+
+
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Promise.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Promise.html new file mode 100644 index 0000000..66d93ab --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Promise.html @@ -0,0 +1,359 @@ + + + + + + +TestEnvironment.Promise (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.Promise<T>

+
+
+ +
+ +
+
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + + + + + + + +
        +
      • +

        value

        +
        public T value()
        +
      • +
      + + + + + + + + + +
        +
      • +

        complete

        +
        public void complete(T value)
        +
        Allows using expectCompletion to await for completion of the value and complete it _then_
        +
      • +
      + + + + + +
        +
      • +

        completeImmediatly

        +
        public void completeImmediatly(T value)
        +
        Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
        +
      • +
      + + + +
        +
      • +

        expectCompletion

        +
        public void expectCompletion(long timeoutMillis,
        +                             java.lang.String errorMsg)
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Receptacle.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Receptacle.html new file mode 100644 index 0000000..c2b8183 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.Receptacle.html @@ -0,0 +1,380 @@ + + + + + + +TestEnvironment.Receptacle (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.Receptacle<T>

+
+
+ +
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      voidadd(T value) 
      voidcomplete() 
      voidexpectCompletion(long timeoutMillis, + java.lang.String errorMsg) 
      <E extends java.lang.Throwable>
      E
      expectError(java.lang.Class<E> clazz, + long timeoutMillis, + java.lang.String errorMsg) 
      voidexpectNone(long withinMillis, + java.lang.String errorMsgPrefix) 
      Tnext(long timeoutMillis, + java.lang.String errorMsg) 
      java.util.List<T>nextN(long elements, + long timeoutMillis, + java.lang.String errorMsg) 
      Optional<T>nextOrEndOfStream(long timeoutMillis, + java.lang.String errorMsg) 
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + + + +
        +
      • +

        add

        +
        public void add(T value)
        +
      • +
      + + + +
        +
      • +

        complete

        +
        public void complete()
        +
      • +
      + + + +
        +
      • +

        next

        +
        public T next(long timeoutMillis,
        +              java.lang.String errorMsg)
        +       throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextOrEndOfStream

        +
        public Optional<TnextOrEndOfStream(long timeoutMillis,
        +                                     java.lang.String errorMsg)
        +                              throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        nextN

        +
        public java.util.List<TnextN(long elements,
        +                               long timeoutMillis,
        +                               java.lang.String errorMsg)
        +                        throws java.lang.InterruptedException
        +
        +
        Parameters:
        +
        timeoutMillis - total timeout time for awaiting all elements number of elements
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectCompletion

        +
        public void expectCompletion(long timeoutMillis,
        +                             java.lang.String errorMsg)
        +                      throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        expectError

        +
        public <E extends java.lang.Throwable> E expectError(java.lang.Class<E> clazz,
        +                                                     long timeoutMillis,
        +                                                     java.lang.String errorMsg)
        +                                              throws java.lang.Exception
        +
        +
        Throws:
        +
        java.lang.Exception
        +
        +
      • +
      + + + +
        +
      • +

        expectNone

        +
        public void expectNone(long withinMillis,
        +                       java.lang.String errorMsgPrefix)
        +                throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html new file mode 100644 index 0000000..cbc5c3a --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html @@ -0,0 +1,388 @@ + + + + + + +TestEnvironment.TestSubscriber (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment.TestSubscriber<T>

+
+
+ +
+ +
+
+
    +
  • + +
      +
    • + + +

      Field Summary

      + + + + + + + + + + +
      Fields 
      Modifier and TypeField and Description
      protected TestEnvironmentenv 
      +
    • +
    + + + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      voidcancel() 
      voidonComplete() 
      voidonError(java.lang.Throwable cause) 
      voidonNext(T element) 
      voidonSubscribe(org.reactivestreams.Subscription subscription) 
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + + + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        onError

        +
        public void onError(java.lang.Throwable cause)
        +
        +
        Specified by:
        +
        onError in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onComplete

        +
        public void onComplete()
        +
        +
        Specified by:
        +
        onComplete in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + + + +
        +
      • +

        onNext

        +
        public void onNext(T element)
        +
        +
        Specified by:
        +
        onNext in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        onSubscribe

        +
        public void onSubscribe(org.reactivestreams.Subscription subscription)
        +
        +
        Specified by:
        +
        onSubscribe in interface org.reactivestreams.Subscriber<T>
        +
        +
      • +
      + + + +
        +
      • +

        cancel

        +
        public void cancel()
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.html new file mode 100644 index 0000000..e490855 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/TestEnvironment.html @@ -0,0 +1,790 @@ + + + + + + +TestEnvironment (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class TestEnvironment

+
+
+ +
+ +
+
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        TestEnvironment

        +
        public TestEnvironment(long defaultTimeoutMillis,
        +                       boolean printlnDebug)
        +
        Tests must specify the timeout for expected outcome of asynchronous + interactions. Longer timeout does not invalidate the correctness of + the implementation, but can in some cases result in longer time to + run the tests.
        +
        +
        Parameters:
        +
        defaultTimeoutMillis - default timeout to be used in all expect* methods
        +
        printlnDebug - if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output, + often helpful to pinpoint simple race conditions etc.
        +
        +
      • +
      + + + +
        +
      • +

        TestEnvironment

        +
        public TestEnvironment(long defaultTimeoutMillis)
        +
        Tests must specify the timeout for expected outcome of asynchronous + interactions. Longer timeout does not invalidate the correctness of + the implementation, but can in some cases result in longer time to + run the tests.
        +
        +
        Parameters:
        +
        defaultTimeoutMillis - default timeout to be used in all expect* methods
        +
        +
      • +
      + + + +
        +
      • +

        TestEnvironment

        +
        public TestEnvironment(boolean printlnDebug)
        +
        Tests must specify the timeout for expected outcome of asynchronous + interactions. Longer timeout does not invalidate the correctness of + the implementation, but can in some cases result in longer time to + run the tests. + + The default timeout for all expect* methods will be obtained by either the env variable DEFAULT_TIMEOUT_MILLIS + or the default value (DEFAULT_TIMEOUT_MILLIS) will be used.
        +
        +
        Parameters:
        +
        printlnDebug - if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output, + often helpful to pinpoint simple race conditions etc.
        +
        +
      • +
      + + + +
        +
      • +

        TestEnvironment

        +
        public TestEnvironment()
        +
        Tests must specify the timeout for expected outcome of asynchronous + interactions. Longer timeout does not invalidate the correctness of + the implementation, but can in some cases result in longer time to + run the tests. + + The default timeout for all expect* methods will be obtained by either the env variable DEFAULT_TIMEOUT_MILLIS + or the default value (DEFAULT_TIMEOUT_MILLIS) will be used.
        +
      • +
      +
    • +
    + +
      +
    • + + +

      Method Detail

      + + + + + + + +
        +
      • +

        envDefaultTimeoutMillis

        +
        public static long envDefaultTimeoutMillis()
        +
        Tries to parse the env variable DEFAULT_TIMEOUT_MILLIS as long and returns the value if present OR its default value.
        +
        +
        Throws:
        +
        java.lang.IllegalArgumentException - when unable to parse the env variable
        +
        +
      • +
      + + + +
        +
      • +

        flop

        +
        public void flop(java.lang.String msg)
        +
        To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously. + This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required. + + Use env.verifyNoAsyncErrorsNoDelay() at the end of your TCK tests to verify there no flops called during it's execution. + To check investigate asyncErrors more closely you can use expectError methods or collect the error directly + from the environment using env.dropAsyncError(). + + To clear asyncErrors you can call clearAsyncErrors()
        +
      • +
      + + + +
        +
      • +

        flop

        +
        public void flop(java.lang.Throwable thr,
        +                 java.lang.String msg)
        +
        To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously. + This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required. + + This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this. + + Use env.verifyNoAsyncErrorsNoDelay() at the end of your TCK tests to verify there no flops called during it's execution. + To check investigate asyncErrors more closely you can use expectError methods or collect the error directly + from the environment using env.dropAsyncError(). + + To clear asyncErrors you can call clearAsyncErrors()
        +
      • +
      + + + +
        +
      • +

        flop

        +
        public void flop(java.lang.Throwable thr)
        +
        To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously. + This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required. + + This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this. + + Use env.verifyNoAsyncErrorsNoDelay() at the end of your TCK tests to verify there no flops called during it's execution. + To check investigate asyncErrors more closely you can use expectError methods or collect the error directly + from the environment using env.dropAsyncError(). + + To clear asyncErrors you can call clearAsyncErrors()
        +
      • +
      + + + +
        +
      • +

        flopAndFail

        +
        public <T> T flopAndFail(java.lang.String msg)
        +
        To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously. + + This method DOES fail the test right away (it tries to, by throwing an AssertionException), + in such it is different from flop(java.lang.String) which only records the error. + + Use env.verifyNoAsyncErrorsNoDelay() at the end of your TCK tests to verify there no flops called during it's execution. + To check investigate asyncErrors more closely you can use expectError methods or collect the error directly + from the environment using env.dropAsyncError(). + + To clear asyncErrors you can call clearAsyncErrors()
        +
      • +
      + + + +
        +
      • +

        subscribe

        +
        public <T> void subscribe(org.reactivestreams.Publisher<T> pub,
        +                          TestEnvironment.TestSubscriber<T> sub)
        +                   throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + +
        +
      • +

        subscribe

        +
        public <T> void subscribe(org.reactivestreams.Publisher<T> pub,
        +                          TestEnvironment.TestSubscriber<T> sub,
        +                          long timeoutMillis)
        +                   throws java.lang.InterruptedException
        +
        +
        Throws:
        +
        java.lang.InterruptedException
        +
        +
      • +
      + + + + + + + + + + + + + + + + + + + + + + + +
        +
      • +

        verifyNoAsyncErrors

        +
        public void verifyNoAsyncErrors()
        +
        Waits for defaultTimeoutMillis() and then verifies that no asynchronous errors + were signalled pior to, or during that time (by calling flop()).
        +
      • +
      + + + +
        +
      • +

        verifyNoAsyncErrors

        +
        public void verifyNoAsyncErrors(long delay)
        +
        This version of verifyNoAsyncErrors should be used when errors still could be signalled + asynchronously during defaultTimeoutMillis() time. +

        + It will immediatly check if any async errors were signaled (using flop(String), + and if no errors encountered wait for another default timeout as the errors may yet be signalled. + The initial check is performed in order to fail-fast in case of an already failed test.
        +
      • +
      + + + +
        +
      • +

        verifyNoAsyncErrorsNoDelay

        +
        public void verifyNoAsyncErrorsNoDelay()
        +
        Verifies that no asynchronous errors were signalled pior to calling this method (by calling flop()). + This version of verifyNoAsyncError does not wait before checking for asynchronous errors, and is to be used + for example in tight loops etc.
        +
      • +
      + + + +
        +
      • +

        debug

        +
        public void debug(java.lang.String msg)
        +
        If TestEnvironment#printlnDebug is true, print debug message to std out.
        +
      • +
      + + + +
        +
      • +

        findCallerMethodInStackTrace

        +
        public Optional<java.lang.StackTraceElement> findCallerMethodInStackTrace(java.lang.String method)
        +
        Looks for given method method in stack trace. + Can be used to answer questions like "was this method called from onComplete?".
        +
        +
        Returns:
        +
        the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/WithHelperPublisher.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/WithHelperPublisher.html new file mode 100644 index 0000000..0454aae --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/WithHelperPublisher.html @@ -0,0 +1,344 @@ + + + + + + +WithHelperPublisher (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck
+

Class WithHelperPublisher<T>

+
+
+ +
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Abstract Methods Concrete Methods 
      Modifier and TypeMethod and Description
      abstract TcreateElement(int element) +
      Implement this method to match your expected element type.
      +
      org.reactivestreams.Publisher<T>createHelperPublisher(long elements) +
      Helper method required for creating the Publisher to which the tested Subscriber will be subscribed and tested against.
      +
      abstract java.util.concurrent.ExecutorServicepublisherExecutorService() +
      ExecutorService to be used by the provided helper Publisher
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        publisherExecutorService

        +
        public abstract java.util.concurrent.ExecutorService publisherExecutorService()
        +
        ExecutorService to be used by the provided helper Publisher
        +
      • +
      + + + +
        +
      • +

        createElement

        +
        public abstract T createElement(int element)
        +
        Implement this method to match your expected element type. + In case of implementing a simple Subscriber which is able to consume any kind of element simply return the + incoming element element. +

        + Sometimes the Subscriber may be limited in what type of element it is able to consume, this you may have to implement + this method such that the emitted element matches the Subscribers requirements. Simplest implementations would be + to simply pass in the element as payload of your custom element, such as appending it to a String or other identifier. +

        + Warning: This method may be called concurrently by the helper publisher, thus it should be implemented in a + thread-safe manner.

        +
        +
        Returns:
        +
        element of the matching type T that will be delivered to the tested Subscriber
        +
        +
      • +
      + + + +
        +
      • +

        createHelperPublisher

        +
        public org.reactivestreams.Publisher<TcreateHelperPublisher(long elements)
        +
        Helper method required for creating the Publisher to which the tested Subscriber will be subscribed and tested against. +

        + By default an asynchronously signalling Publisher is provided, which will use createElement(int) + to generate elements type your Subscriber is able to consume. +

        + Sometimes you may want to implement your own custom custom helper Publisher - to validate behaviour of a Subscriber + when facing a synchronous Publisher for example. If you do, it MUST emit the exact number of elements asked for + (via the elements parameter) and MUST also must treat the following numbers of elements in these specific ways: +

          +
        • + If elements is Long.MAX_VALUE the produced stream must be infinite. +
        • +
        • + If elements is 0 the Publisher should signal onComplete immediatly. + In other words, it should represent a "completed stream". +
        • +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-frame.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-frame.html new file mode 100644 index 0000000..1c23d04 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-frame.html @@ -0,0 +1,43 @@ + + + + + + +org.reactivestreams.tck (reactive-streams-tck 1.0.0 API) + + + + +

org.reactivestreams.tck

+
+

Interfaces

+ +

Classes

+ +
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-summary.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-summary.html new file mode 100644 index 0000000..258a92f --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-summary.html @@ -0,0 +1,251 @@ + + + + + + +org.reactivestreams.tck (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Package org.reactivestreams.tck

+
+
+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-tree.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-tree.html new file mode 100644 index 0000000..f7e1ac5 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/package-tree.html @@ -0,0 +1,180 @@ + + + + + + +org.reactivestreams.tck Class Hierarchy (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For Package org.reactivestreams.tck

+Package Hierarchies: + +
+
+

Class Hierarchy

+ +

Interface Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Function.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Function.html new file mode 100644 index 0000000..50851bc --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Function.html @@ -0,0 +1,226 @@ + + + + + + +Function (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Interface Function<In,Out>

+
+
+
+
    +
  • +
    +
    +
    public interface Function<In,Out>
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + + + +
        +
      • +

        apply

        +
        Out apply(In in)
        +   throws java.lang.Throwable
        +
        +
        Throws:
        +
        java.lang.Throwable
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/HelperPublisher.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/HelperPublisher.html new file mode 100644 index 0000000..f567228 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/HelperPublisher.html @@ -0,0 +1,257 @@ + + + + + + +HelperPublisher (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class HelperPublisher<T>

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    org.reactivestreams.Publisher<T>
    +
    +
    +
    +
    public class HelperPublisher<T>
    +extends org.reactivestreams.example.unicast.AsyncIterablePublisher<T>
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      HelperPublisher(int from, + int to, + Function<java.lang.Integer,T> create, + java.util.concurrent.Executor executor) 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      +
        +
      • + + +

        Methods inherited from class org.reactivestreams.example.unicast.AsyncIterablePublisher

        +subscribe
      • +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Detail

      + + + +
        +
      • +

        HelperPublisher

        +
        public HelperPublisher(int from,
        +                       int to,
        +                       Function<java.lang.Integer,T> create,
        +                       java.util.concurrent.Executor executor)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/InfiniteHelperPublisher.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/InfiniteHelperPublisher.html new file mode 100644 index 0000000..1dffec6 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/InfiniteHelperPublisher.html @@ -0,0 +1,253 @@ + + + + + + +InfiniteHelperPublisher (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class InfiniteHelperPublisher<T>

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    org.reactivestreams.Publisher<T>
    +
    +
    +
    +
    public class InfiniteHelperPublisher<T>
    +extends org.reactivestreams.example.unicast.AsyncIterablePublisher<T>
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      InfiniteHelperPublisher(Function<java.lang.Integer,T> create, + java.util.concurrent.Executor executor) 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      +
        +
      • + + +

        Methods inherited from class org.reactivestreams.example.unicast.AsyncIterablePublisher

        +subscribe
      • +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/NonFatal.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/NonFatal.html new file mode 100644 index 0000000..ab510e1 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/NonFatal.html @@ -0,0 +1,245 @@ + + + + + + +NonFatal (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class NonFatal

+
+
+ +
+
    +
  • +
    +
    +
    public class NonFatal
    +extends java.lang.Object
    +
    Copy of scala.control.util.NonFatal in order to not depend on scala-library
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + +
      All Methods Static Methods Concrete Methods 
      Modifier and TypeMethod and Description
      static booleanisNonFatal(java.lang.Throwable t) +
      Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
      +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + +
        +
      • +

        isNonFatal

        +
        public static boolean isNonFatal(java.lang.Throwable t)
        +
        Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
        +
        +
        Parameters:
        +
        t - throwable to be matched for fatal-ness
        +
        Returns:
        +
        true if is a non-fatal throwable, false otherwise
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.Some.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.Some.html new file mode 100644 index 0000000..2e7efe5 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.Some.html @@ -0,0 +1,304 @@ + + + + + + +Optional.Some (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class Optional.Some<T>

+
+
+ +
+ +
+
+
    +
  • + +
      +
    • + + +

      Nested Class Summary

      + +
    • +
    + +
      +
    • + + +

      Method Summary

      + + + + + + + + + + + + + + + + + + +
      All Methods Instance Methods Concrete Methods 
      Modifier and TypeMethod and Description
      Tget() 
      booleanisEmpty() 
      java.lang.StringtoString() 
      + +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.html new file mode 100644 index 0000000..ef9fb5c --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/Optional.html @@ -0,0 +1,329 @@ + + + + + + +Optional (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class Optional<T>

+
+
+ +
+
    +
  • +
    +
    Direct Known Subclasses:
    +
    Optional.Some
    +
    +
    +
    +
    public abstract class Optional<T>
    +extends java.lang.Object
    +
  • +
+
+
+ +
+
+
    +
  • + +
      +
    • + + +

      Method Detail

      + + + + + + + + + +
        +
      • +

        of

        +
        public static <T> Optional<T> of(T it)
        +
      • +
      + + + +
        +
      • +

        get

        +
        public abstract T get()
        +
      • +
      + + + +
        +
      • +

        isEmpty

        +
        public abstract boolean isEmpty()
        +
      • +
      + + + +
        +
      • +

        isDefined

        +
        public boolean isDefined()
        +
      • +
      + + + +
        +
      • +

        toString

        +
        public java.lang.String toString()
        +
        +
        Overrides:
        +
        toString in class java.lang.Object
        +
        +
      • +
      +
    • +
    +
  • +
+
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/PublisherVerificationRules.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/PublisherVerificationRules.html new file mode 100644 index 0000000..f6668f7 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/PublisherVerificationRules.html @@ -0,0 +1,860 @@ + + + + + + +PublisherVerificationRules (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Interface PublisherVerificationRules

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html new file mode 100644 index 0000000..62503fc --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html @@ -0,0 +1,662 @@ + + + + + + +SubscriberBlackboxVerificationRules (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Interface SubscriberBlackboxVerificationRules

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html new file mode 100644 index 0000000..b20b45b --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html @@ -0,0 +1,303 @@ + + + + + + +SubscriberBufferOverflowException (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class SubscriberBufferOverflowException

+
+
+ +
+ +
+
+
    +
  • + + + +
      +
    • + + +

      Method Summary

      +
        +
      • + + +

        Methods inherited from class java.lang.Throwable

        +addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString
      • +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html new file mode 100644 index 0000000..7135b88 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html @@ -0,0 +1,698 @@ + + + + + + +SubscriberWhiteboxVerificationRules (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Interface SubscriberWhiteboxVerificationRules

+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/TestException.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/TestException.html new file mode 100644 index 0000000..8f3584f --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/TestException.html @@ -0,0 +1,267 @@ + + + + + + +TestException (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + + +
+
org.reactivestreams.tck.support
+

Class TestException

+
+
+ +
+
    +
  • +
    +
    All Implemented Interfaces:
    +
    java.io.Serializable
    +
    +
    +
    +
    public final class TestException
    +extends java.lang.RuntimeException
    +
    Exception used by the TCK to signal failures. + May be thrown or signalled through Subscriber.onError(Throwable).
    +
    +
    See Also:
    +
    Serialized Form
    +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      Constructor Summary

      + + + + + + + + +
      Constructors 
      Constructor and Description
      TestException() 
      +
    • +
    + +
      +
    • + + +

      Method Summary

      +
        +
      • + + +

        Methods inherited from class java.lang.Throwable

        +addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString
      • +
      +
        +
      • + + +

        Methods inherited from class java.lang.Object

        +clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+ +
+
+ + +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-frame.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-frame.html new file mode 100644 index 0000000..4c4bacb --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-frame.html @@ -0,0 +1,36 @@ + + + + + + +org.reactivestreams.tck.support (reactive-streams-tck 1.0.0 API) + + + + +

org.reactivestreams.tck.support

+
+

Interfaces

+ +

Classes

+ +

Exceptions

+ +
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-summary.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-summary.html new file mode 100644 index 0000000..f414132 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-summary.html @@ -0,0 +1,212 @@ + + + + + + +org.reactivestreams.tck.support (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Package org.reactivestreams.tck.support

+
+
+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-tree.html b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-tree.html new file mode 100644 index 0000000..3a2e188 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/org/reactivestreams/tck/support/package-tree.html @@ -0,0 +1,167 @@ + + + + + + +org.reactivestreams.tck.support Class Hierarchy (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For Package org.reactivestreams.tck.support

+Package Hierarchies: + +
+
+

Class Hierarchy

+ +

Interface Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/overview-frame.html b/reactive-streams-tck-1.0.0-javadoc/overview-frame.html new file mode 100644 index 0000000..438a110 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/overview-frame.html @@ -0,0 +1,22 @@ + + + + + + +Overview List (reactive-streams-tck 1.0.0 API) + + + + +
All Classes
+
+

Packages

+ +
+

 

+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/overview-summary.html b/reactive-streams-tck-1.0.0-javadoc/overview-summary.html new file mode 100644 index 0000000..799b86f --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/overview-summary.html @@ -0,0 +1,140 @@ + + + + + + +Overview (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

reactive-streams-tck 1.0.0 API

+
+
+ + + + + + + + + + + + + + + + +
Packages 
PackageDescription
org.reactivestreams.tck 
org.reactivestreams.tck.support 
+
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/overview-tree.html b/reactive-streams-tck-1.0.0-javadoc/overview-tree.html new file mode 100644 index 0000000..469bb58 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/overview-tree.html @@ -0,0 +1,211 @@ + + + + + + +Class Hierarchy (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Hierarchy For All Packages

+Package Hierarchies: + +
+
+

Class Hierarchy

+ +

Interface Hierarchy

+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/package-list b/reactive-streams-tck-1.0.0-javadoc/package-list new file mode 100644 index 0000000..6d65260 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/package-list @@ -0,0 +1,2 @@ +org.reactivestreams.tck +org.reactivestreams.tck.support diff --git a/reactive-streams-tck-1.0.0-javadoc/script.js b/reactive-streams-tck-1.0.0-javadoc/script.js new file mode 100644 index 0000000..b346356 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/script.js @@ -0,0 +1,30 @@ +function show(type) +{ + count = 0; + for (var key in methods) { + var row = document.getElementById(key); + if ((methods[key] & type) != 0) { + row.style.display = ''; + row.className = (count++ % 2) ? rowColor : altColor; + } + else + row.style.display = 'none'; + } + updateTabs(type); +} + +function updateTabs(type) +{ + for (var value in tabs) { + var sNode = document.getElementById(tabs[value][0]); + var spanNode = sNode.firstChild; + if (value == type) { + sNode.className = activeTableTab; + spanNode.innerHTML = tabs[value][1]; + } + else { + sNode.className = tableTab; + spanNode.innerHTML = "" + tabs[value][1] + ""; + } + } +} diff --git a/reactive-streams-tck-1.0.0-javadoc/serialized-form.html b/reactive-streams-tck-1.0.0-javadoc/serialized-form.html new file mode 100644 index 0000000..e8d1242 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/serialized-form.html @@ -0,0 +1,140 @@ + + + + + + +Serialized Form (reactive-streams-tck 1.0.0 API) + + + + + + + +
+ + + + + + + +
+ + +
+

Serialized Form

+
+
+ +
+ +
+ + + + + + + +
+ + + + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html new file mode 100644 index 0000000..869e3e1 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.ManualSubscriberWithErrorCollection.html @@ -0,0 +1,834 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Processor;
+004import org.reactivestreams.Publisher;
+005import org.reactivestreams.Subscriber;
+006import org.reactivestreams.Subscription;
+007import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+008import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+009import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+010import org.reactivestreams.tck.TestEnvironment.Promise;
+011import org.reactivestreams.tck.support.Function;
+012import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+013import org.reactivestreams.tck.support.PublisherVerificationRules;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.util.HashSet;
+018import java.util.Set;
+019
+020public abstract class IdentityProcessorVerification<T> extends WithHelperPublisher<T>
+021  implements SubscriberWhiteboxVerificationRules, PublisherVerificationRules {
+022
+023  private final TestEnvironment env;
+024
+025  ////////////////////// DELEGATED TO SPECS //////////////////////
+026
+027  // for delegating tests
+028  private final SubscriberWhiteboxVerification<T> subscriberVerification;
+029
+030  // for delegating tests
+031  private final PublisherVerification<T> publisherVerification;
+032
+033  ////////////////// END OF DELEGATED TO SPECS //////////////////
+034
+035  // number of elements the processor under test must be able ot buffer,
+036  // without dropping elements. Defaults to `TestEnvironment.TEST_BUFFER_SIZE`.
+037  private final int processorBufferSize;
+038
+039  /**
+040   * Test class must specify the expected time it takes for the publisher to
+041   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+042   *
+043   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+044   */
+045  @SuppressWarnings("unused")
+046  public IdentityProcessorVerification(final TestEnvironment env) {
+047    this(env, PublisherVerification.envPublisherReferenceGCTimeoutMillis(), TestEnvironment.TEST_BUFFER_SIZE);
+048  }
+049
+050  /**
+051   * Test class must specify the expected time it takes for the publisher to
+052   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+053   *
+054   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+055   *
+056   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+057   */
+058  @SuppressWarnings("unused")
+059  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+060    this(env, publisherReferenceGCTimeoutMillis, TestEnvironment.TEST_BUFFER_SIZE);
+061  }
+062
+063  /**
+064   * Test class must specify the expected time it takes for the publisher to
+065   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+066   *
+067   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+068   * @param processorBufferSize            number of elements the processor is required to be able to buffer.
+069   */
+070  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis, int processorBufferSize) {
+071    this.env = env;
+072    this.processorBufferSize = processorBufferSize;
+073
+074    this.subscriberVerification = new SubscriberWhiteboxVerification<T>(env) {
+075      @Override
+076      public Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe) {
+077        return IdentityProcessorVerification.this.createSubscriber(probe);
+078      }
+079
+080      @Override public T createElement(int element) {
+081        return IdentityProcessorVerification.this.createElement(element);
+082      }
+083
+084      @Override
+085      public Publisher<T> createHelperPublisher(long elements) {
+086        return IdentityProcessorVerification.this.createHelperPublisher(elements);
+087      }
+088    };
+089
+090    publisherVerification = new PublisherVerification<T>(env, publisherReferenceGCTimeoutMillis) {
+091      @Override
+092      public Publisher<T> createPublisher(long elements) {
+093        return IdentityProcessorVerification.this.createPublisher(elements);
+094      }
+095
+096      @Override
+097      public Publisher<T> createFailedPublisher() {
+098        return IdentityProcessorVerification.this.createFailedPublisher();
+099      }
+100
+101      @Override
+102      public long maxElementsFromPublisher() {
+103        return IdentityProcessorVerification.this.maxElementsFromPublisher();
+104      }
+105
+106      @Override
+107      public long boundedDepthOfOnNextAndRequestRecursion() {
+108        return IdentityProcessorVerification.this.boundedDepthOfOnNextAndRequestRecursion();
+109      }
+110
+111      @Override
+112      public boolean skipStochasticTests() {
+113        return IdentityProcessorVerification.this.skipStochasticTests();
+114      }
+115    };
+116  }
+117
+118  /**
+119   * This is the main method you must implement in your test incarnation.
+120   * It must create a Publisher, which simply forwards all stream elements from its upstream
+121   * to its downstream. It must be able to internally buffer the given number of elements.
+122   *
+123   * @param bufferSize number of elements the processor is required to be able to buffer.
+124   */
+125  public abstract Processor<T, T> createIdentityProcessor(int bufferSize);
+126
+127  /**
+128   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+129   *
+130   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+131   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+132   *
+133   * If you ignore these additional tests, return {@code null} from this method.
+134   */
+135  public abstract Publisher<T> createFailedPublisher();
+136
+137  /**
+138   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+139   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+140   *
+141   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+142   *
+143   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+144   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+145   */
+146  public long maxElementsFromPublisher() {
+147    return Long.MAX_VALUE - 1;
+148  }
+149
+150  /**
+151   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+152   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+153   * recursive calls to exceed the number returned by this method.
+154   *
+155   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+156   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+157   */
+158  public long boundedDepthOfOnNextAndRequestRecursion() {
+159    return 1;
+160  }
+161
+162  /**
+163   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+164   * Such tests MAY sometimes fail even though the impl
+165   */
+166  public boolean skipStochasticTests() {
+167    return false;
+168  }
+169
+170  /**
+171   * Describes the tested implementation in terms of how many subscribers they can support.
+172   * Some tests require the {@code Publisher} under test to support multiple Subscribers,
+173   * yet the spec does not require all publishers to be able to do so, thus – if an implementation
+174   * supports only a limited number of subscribers (e.g. only 1 subscriber, also known as "no fanout")
+175   * you MUST return that number from this method by overriding it.
+176   */
+177  public long maxSupportedSubscribers() {
+178      return Long.MAX_VALUE;
+179  }
+180
+181  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+182
+183  @BeforeMethod
+184  public void setUp() throws Exception {
+185    publisherVerification.setUp();
+186    subscriberVerification.setUp();
+187  }
+188
+189  ////////////////////// PUBLISHER RULES VERIFICATION ///////////////////////////
+190
+191  // A Processor
+192  //   must obey all Publisher rules on its publishing side
+193  public Publisher<T> createPublisher(long elements) {
+194    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+195    final Publisher<T> pub = createHelperPublisher(elements);
+196    pub.subscribe(processor);
+197    return processor; // we run the PublisherVerification against this
+198  }
+199
+200  @Override @Test
+201  public void required_validate_maxElementsFromPublisher() throws Exception {
+202    publisherVerification.required_validate_maxElementsFromPublisher();
+203  }
+204
+205  @Override @Test
+206  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+207    publisherVerification.required_validate_boundedDepthOfOnNextAndRequestRecursion();
+208  }
+209
+210  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" PUBLISHER //////////////////////
+211  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+212
+213  @Test
+214  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+215    publisherVerification.required_createPublisher1MustProduceAStreamOfExactly1Element();
+216  }
+217
+218  @Test
+219  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+220    publisherVerification.required_createPublisher3MustProduceAStreamOfExactly3Elements();
+221  }
+222
+223  @Override @Test
+224  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+225    publisherVerification.required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements();
+226  }
+227
+228  @Override @Test
+229  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+230    publisherVerification.required_spec102_maySignalLessThanRequestedAndTerminateSubscription();
+231  }
+232
+233  @Override @Test
+234  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+235    publisherVerification.stochastic_spec103_mustSignalOnMethodsSequentially();
+236  }
+237
+238  @Override @Test
+239  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+240    publisherVerification.optional_spec104_mustSignalOnErrorWhenFails();
+241  }
+242
+243  @Override @Test
+244  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+245    publisherVerification.required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates();
+246  }
+247
+248  @Override @Test
+249  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+250    publisherVerification.optional_spec105_emptyStreamMustTerminateBySignallingOnComplete();
+251  }
+252
+253  @Override @Test
+254  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+255    publisherVerification.untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled();
+256  }
+257
+258  @Override @Test
+259  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+260    publisherVerification.required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled();
+261  }
+262
+263  @Override @Test
+264  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+265    publisherVerification.untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled();
+266  }
+267
+268  @Override @Test
+269  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+270    publisherVerification.untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals();
+271  }
+272
+273  @Override @Test
+274  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+275    publisherVerification.untested_spec109_subscribeShouldNotThrowNonFatalThrowable();
+276  }
+277
+278  @Override @Test
+279  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+280    publisherVerification.required_spec109_subscribeThrowNPEOnNullSubscriber();
+281  }
+282
+283  @Override @Test
+284  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+285    publisherVerification.required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe();
+286  }
+287
+288  @Override @Test
+289  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+290    publisherVerification.required_spec109_mustIssueOnSubscribeForNonNullSubscriber();
+291  }
+292
+293  @Override @Test
+294  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+295    publisherVerification.untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice();
+296  }
+297
+298  @Override @Test
+299  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+300    publisherVerification.optional_spec111_maySupportMultiSubscribe();
+301  }
+302
+303  @Override @Test
+304  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+305    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne();
+306  }
+307
+308  @Override @Test
+309  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+310    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront();
+311  }
+312
+313  @Override @Test
+314  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+315    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected();
+316  }
+317
+318  @Override @Test
+319  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+320    publisherVerification.required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe();
+321  }
+322
+323  @Override @Test
+324  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+325    publisherVerification.required_spec303_mustNotAllowUnboundedRecursion();
+326  }
+327
+328  @Override @Test
+329  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+330    publisherVerification.untested_spec304_requestShouldNotPerformHeavyComputations();
+331  }
+332
+333  @Override @Test
+334  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() throws Exception {
+335    publisherVerification.untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation();
+336  }
+337
+338  @Override @Test
+339  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+340    publisherVerification.required_spec306_afterSubscriptionIsCancelledRequestMustBeNops();
+341  }
+342
+343  @Override @Test
+344  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+345    publisherVerification.required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops();
+346  }
+347
+348  @Override @Test
+349  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+350    publisherVerification.required_spec309_requestZeroMustSignalIllegalArgumentException();
+351  }
+352
+353  @Override @Test
+354  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+355    publisherVerification.required_spec309_requestNegativeNumberMustSignalIllegalArgumentException();
+356  }
+357
+358  @Override @Test
+359  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+360    publisherVerification.required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling();
+361  }
+362
+363  @Override @Test
+364  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+365    publisherVerification.required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber();
+366  }
+367
+368  @Override @Test
+369  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+370    publisherVerification.required_spec317_mustSupportAPendingElementCountUpToLongMaxValue();
+371  }
+372
+373  @Override @Test
+374  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+375    publisherVerification.required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue();
+376  }
+377
+378  @Override @Test
+379  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+380    publisherVerification.required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue();
+381  }
+382
+383  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.4
+384  // for multiple subscribers
+385  @Test
+386  public void required_spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError() throws Throwable {
+387    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+388      @Override
+389      public TestSetup apply(Long aLong) throws Throwable {
+390        return new TestSetup(env, processorBufferSize) {{
+391          final ManualSubscriberWithErrorCollection<T> sub1 = new ManualSubscriberWithErrorCollection<T>(env);
+392          env.subscribe(processor, sub1);
+393
+394          final ManualSubscriberWithErrorCollection<T> sub2 = new ManualSubscriberWithErrorCollection<T>(env);
+395          env.subscribe(processor, sub2);
+396
+397          sub1.request(1);
+398          expectRequest();
+399          final T x = sendNextTFromUpstream();
+400          expectNextElement(sub1, x);
+401          sub1.request(1);
+402
+403          // sub1 has received one element, and has one demand pending
+404          // sub2 has not yet requested anything
+405
+406          final Exception ex = new RuntimeException("Test exception");
+407          sendError(ex);
+408          sub1.expectError(ex);
+409          sub2.expectError(ex);
+410
+411          env.verifyNoAsyncErrorsNoDelay();
+412        }};
+413      }
+414    });
+415  }
+416
+417  ////////////////////// SUBSCRIBER RULES VERIFICATION ///////////////////////////
+418  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+419
+420  // A Processor
+421  //   must obey all Subscriber rules on its consuming side
+422  public Subscriber<T> createSubscriber(final SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T> probe) {
+423    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+424    processor.subscribe(
+425        new Subscriber<T>() {
+426          private final Promise<Subscription> subs = new Promise<Subscription>(env);
+427
+428          @Override
+429          public void onSubscribe(final Subscription subscription) {
+430            env.debug(String.format("whiteboxSubscriber::onSubscribe(%s)", subscription));
+431            if (subs.isCompleted()) subscription.cancel(); // the Probe must also pass subscriber verification
+432
+433            probe.registerOnSubscribe(new SubscriberWhiteboxVerification.SubscriberPuppet() {
+434
+435              @Override
+436              public void triggerRequest(long elements) {
+437                subscription.request(elements);
+438              }
+439
+440              @Override
+441              public void signalCancel() {
+442                subscription.cancel();
+443              }
+444            });
+445          }
+446
+447          @Override
+448          public void onNext(T element) {
+449            env.debug(String.format("whiteboxSubscriber::onNext(%s)", element));
+450            probe.registerOnNext(element);
+451          }
+452
+453          @Override
+454          public void onComplete() {
+455            env.debug("whiteboxSubscriber::onComplete()");
+456            probe.registerOnComplete();
+457          }
+458
+459          @Override
+460          public void onError(Throwable cause) {
+461            env.debug(String.format("whiteboxSubscriber::onError(%s)", cause));
+462            probe.registerOnError(cause);
+463          }
+464        });
+465
+466    return processor; // we run the SubscriberVerification against this
+467  }
+468
+469  ////////////////////// OTHER RULE VERIFICATION ///////////////////////////
+470
+471  // A Processor
+472  //   must immediately pass on `onError` events received from its upstream to its downstream
+473  @Test
+474  public void mustImmediatelyPassOnOnErrorEventsReceivedFromItsUpstreamToItsDownstream() throws Exception {
+475    new TestSetup(env, processorBufferSize) {{
+476      final ManualSubscriberWithErrorCollection<T> sub = new ManualSubscriberWithErrorCollection<T>(env);
+477      env.subscribe(processor, sub);
+478
+479      final Exception ex = new RuntimeException("Test exception");
+480      sendError(ex);
+481      sub.expectError(ex); // "immediately", i.e. without a preceding request
+482
+483      env.verifyNoAsyncErrorsNoDelay();
+484    }};
+485  }
+486
+487  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" SUBSCRIBER //////////////////////
+488  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+489
+490  @Test
+491  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+492    subscriberVerification.required_exerciseWhiteboxHappyPath();
+493  }
+494
+495  @Override @Test
+496  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+497    subscriberVerification.required_spec201_mustSignalDemandViaSubscriptionRequest();
+498  }
+499
+500  @Override @Test
+501  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+502    subscriberVerification.untested_spec202_shouldAsynchronouslyDispatch();
+503  }
+504
+505  @Override @Test
+506  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+507    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete();
+508  }
+509
+510  @Override @Test
+511  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+512    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError();
+513  }
+514
+515  @Override @Test
+516  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+517    subscriberVerification.untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError();
+518  }
+519
+520  @Override @Test
+521  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+522    subscriberVerification.required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal();
+523  }
+524
+525  @Override @Test
+526  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+527    subscriberVerification.untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid();
+528  }
+529
+530  @Override @Test
+531  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+532    subscriberVerification.untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization();
+533  }
+534
+535  @Override @Test
+536  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+537    subscriberVerification.required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel();
+538  }
+539
+540  @Override @Test
+541  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+542    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall();
+543  }
+544
+545  @Override @Test
+546  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+547    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall();
+548  }
+549
+550  @Override @Test
+551  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+552    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall();
+553  }
+554
+555  @Override @Test
+556  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+557    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall();
+558  }
+559
+560  @Override @Test
+561  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+562    subscriberVerification.untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents();
+563  }
+564
+565  @Override @Test
+566  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+567    subscriberVerification.untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation();
+568  }
+569
+570  @Override @Test
+571  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+572    subscriberVerification.untested_spec213_failingOnSignalInvocation();
+573  }
+574
+575  @Override @Test
+576  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+577    subscriberVerification.required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull();
+578  }
+579  @Override @Test
+580  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+581    subscriberVerification.required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull();
+582  }
+583  @Override @Test
+584  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+585    subscriberVerification.required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull();
+586  }
+587
+588  @Override @Test
+589  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+590    subscriberVerification.untested_spec301_mustNotBeCalledOutsideSubscriberContext();
+591  }
+592
+593  @Override @Test
+594  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+595    subscriberVerification.required_spec308_requestMustRegisterGivenNumberElementsToBeProduced();
+596  }
+597
+598  @Override @Test
+599  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+600    subscriberVerification.untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber();
+601  }
+602
+603  @Override @Test
+604  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+605    subscriberVerification.untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError();
+606  }
+607
+608  @Override @Test
+609  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+610    subscriberVerification.untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists();
+611  }
+612
+613  @Override @Test
+614  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+615    subscriberVerification.untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError();
+616  }
+617
+618  @Override @Test
+619  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+620    subscriberVerification.untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber();
+621  }
+622
+623  /////////////////////// ADDITIONAL "COROLLARY" TESTS //////////////////////
+624
+625  // A Processor
+626  //   must trigger `requestFromUpstream` for elements that have been requested 'long ago'
+627  @Test
+628  public void required_mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo() throws Throwable {
+629    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+630      @Override
+631      public TestSetup apply(Long subscribers) throws Throwable {
+632        return new TestSetup(env, processorBufferSize) {{
+633          ManualSubscriber<T> sub1 = newSubscriber();
+634          sub1.request(20);
+635
+636          long totalRequests = expectRequest();
+637          final T x = sendNextTFromUpstream();
+638          expectNextElement(sub1, x);
+639
+640          if (totalRequests == 1) {
+641            totalRequests += expectRequest();
+642          }
+643          final T y = sendNextTFromUpstream();
+644          expectNextElement(sub1, y);
+645
+646          if (totalRequests == 2) {
+647            totalRequests += expectRequest();
+648          }
+649
+650          final ManualSubscriber<T> sub2 = newSubscriber();
+651
+652          // sub1 now has 18 pending
+653          // sub2 has 0 pending
+654
+655          final T z = sendNextTFromUpstream();
+656          expectNextElement(sub1, z);
+657          sub2.expectNone(); // since sub2 hasn't requested anything yet
+658
+659          sub2.request(1);
+660          expectNextElement(sub2, z);
+661
+662          if (totalRequests == 3) {
+663            expectRequest();
+664          }
+665
+666          // to avoid error messages during test harness shutdown
+667          sendCompletion();
+668          sub1.expectCompletion(env.defaultTimeoutMillis());
+669          sub2.expectCompletion(env.defaultTimeoutMillis());
+670
+671          env.verifyNoAsyncErrorsNoDelay();
+672        }};
+673      }
+674    });
+675  }
+676
+677  /////////////////////// TEST INFRASTRUCTURE //////////////////////
+678
+679  public void notVerified() {
+680    publisherVerification.notVerified();
+681  }
+682
+683  public void notVerified(String message) {
+684    publisherVerification.notVerified(message);
+685  }
+686
+687  /**
+688   * Test for feature that REQUIRES multiple subscribers to be supported by Publisher.
+689   */
+690  public void optionalMultipleSubscribersTest(long requiredSubscribersSupport, Function<Long, TestSetup> body) throws Throwable {
+691    if (requiredSubscribersSupport > maxSupportedSubscribers())
+692      notVerified(String.format("The Publisher under test only supports %d subscribers, while this test requires at least %d to run.",
+693                                maxSupportedSubscribers(), requiredSubscribersSupport));
+694    else body.apply(requiredSubscribersSupport);
+695  }
+696
+697  public abstract class TestSetup extends ManualPublisher<T> {
+698    final private ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+699    private Set<T> seenTees = new HashSet<T>();
+700
+701    final Processor<T, T> processor;
+702
+703    public TestSetup(TestEnvironment env, int testBufferSize) throws InterruptedException {
+704      super(env);
+705      tees = env.newManualSubscriber(createHelperPublisher(Long.MAX_VALUE));
+706      processor = createIdentityProcessor(testBufferSize);
+707      subscribe(processor);
+708    }
+709
+710    public ManualSubscriber<T> newSubscriber() throws InterruptedException {
+711      return env.newManualSubscriber(processor);
+712    }
+713
+714    public T nextT() throws InterruptedException {
+715      final T t = tees.requestNextElement();
+716      if (seenTees.contains(t)) {
+717        env.flop(String.format("Helper publisher illegally produced the same element %s twice", t));
+718      }
+719      seenTees.add(t);
+720      return t;
+721    }
+722
+723    public void expectNextElement(ManualSubscriber<T> sub, T expected) throws InterruptedException {
+724      final T elem = sub.nextElement(String.format("timeout while awaiting %s", expected));
+725      if (!elem.equals(expected)) {
+726        env.flop(String.format("Received `onNext(%s)` on downstream but expected `onNext(%s)`", elem, expected));
+727      }
+728    }
+729
+730    public T sendNextTFromUpstream() throws InterruptedException {
+731      final T x = nextT();
+732      sendNext(x);
+733      return x;
+734    }
+735  }
+736
+737  public class ManualSubscriberWithErrorCollection<A> extends ManualSubscriberWithSubscriptionSupport<A> {
+738    Promise<Throwable> error;
+739
+740    public ManualSubscriberWithErrorCollection(TestEnvironment env) {
+741      super(env);
+742      error = new Promise<Throwable>(env);
+743    }
+744
+745    @Override
+746    public void onError(Throwable cause) {
+747      error.complete(cause);
+748    }
+749
+750    public void expectError(Throwable cause) throws InterruptedException {
+751      expectError(cause, env.defaultTimeoutMillis());
+752    }
+753
+754    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+755    public void expectError(Throwable cause, long timeoutMillis) throws InterruptedException {
+756      error.expectCompletion(timeoutMillis, "Did not receive expected error on downstream");
+757      if (!cause.equals(error.value())) {
+758        env.flop(String.format("Expected error %s but got %s", cause, error.value()));
+759      }
+760    }
+761  }
+762}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html new file mode 100644 index 0000000..869e3e1 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.TestSetup.html @@ -0,0 +1,834 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Processor;
+004import org.reactivestreams.Publisher;
+005import org.reactivestreams.Subscriber;
+006import org.reactivestreams.Subscription;
+007import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+008import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+009import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+010import org.reactivestreams.tck.TestEnvironment.Promise;
+011import org.reactivestreams.tck.support.Function;
+012import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+013import org.reactivestreams.tck.support.PublisherVerificationRules;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.util.HashSet;
+018import java.util.Set;
+019
+020public abstract class IdentityProcessorVerification<T> extends WithHelperPublisher<T>
+021  implements SubscriberWhiteboxVerificationRules, PublisherVerificationRules {
+022
+023  private final TestEnvironment env;
+024
+025  ////////////////////// DELEGATED TO SPECS //////////////////////
+026
+027  // for delegating tests
+028  private final SubscriberWhiteboxVerification<T> subscriberVerification;
+029
+030  // for delegating tests
+031  private final PublisherVerification<T> publisherVerification;
+032
+033  ////////////////// END OF DELEGATED TO SPECS //////////////////
+034
+035  // number of elements the processor under test must be able ot buffer,
+036  // without dropping elements. Defaults to `TestEnvironment.TEST_BUFFER_SIZE`.
+037  private final int processorBufferSize;
+038
+039  /**
+040   * Test class must specify the expected time it takes for the publisher to
+041   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+042   *
+043   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+044   */
+045  @SuppressWarnings("unused")
+046  public IdentityProcessorVerification(final TestEnvironment env) {
+047    this(env, PublisherVerification.envPublisherReferenceGCTimeoutMillis(), TestEnvironment.TEST_BUFFER_SIZE);
+048  }
+049
+050  /**
+051   * Test class must specify the expected time it takes for the publisher to
+052   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+053   *
+054   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+055   *
+056   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+057   */
+058  @SuppressWarnings("unused")
+059  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+060    this(env, publisherReferenceGCTimeoutMillis, TestEnvironment.TEST_BUFFER_SIZE);
+061  }
+062
+063  /**
+064   * Test class must specify the expected time it takes for the publisher to
+065   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+066   *
+067   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+068   * @param processorBufferSize            number of elements the processor is required to be able to buffer.
+069   */
+070  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis, int processorBufferSize) {
+071    this.env = env;
+072    this.processorBufferSize = processorBufferSize;
+073
+074    this.subscriberVerification = new SubscriberWhiteboxVerification<T>(env) {
+075      @Override
+076      public Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe) {
+077        return IdentityProcessorVerification.this.createSubscriber(probe);
+078      }
+079
+080      @Override public T createElement(int element) {
+081        return IdentityProcessorVerification.this.createElement(element);
+082      }
+083
+084      @Override
+085      public Publisher<T> createHelperPublisher(long elements) {
+086        return IdentityProcessorVerification.this.createHelperPublisher(elements);
+087      }
+088    };
+089
+090    publisherVerification = new PublisherVerification<T>(env, publisherReferenceGCTimeoutMillis) {
+091      @Override
+092      public Publisher<T> createPublisher(long elements) {
+093        return IdentityProcessorVerification.this.createPublisher(elements);
+094      }
+095
+096      @Override
+097      public Publisher<T> createFailedPublisher() {
+098        return IdentityProcessorVerification.this.createFailedPublisher();
+099      }
+100
+101      @Override
+102      public long maxElementsFromPublisher() {
+103        return IdentityProcessorVerification.this.maxElementsFromPublisher();
+104      }
+105
+106      @Override
+107      public long boundedDepthOfOnNextAndRequestRecursion() {
+108        return IdentityProcessorVerification.this.boundedDepthOfOnNextAndRequestRecursion();
+109      }
+110
+111      @Override
+112      public boolean skipStochasticTests() {
+113        return IdentityProcessorVerification.this.skipStochasticTests();
+114      }
+115    };
+116  }
+117
+118  /**
+119   * This is the main method you must implement in your test incarnation.
+120   * It must create a Publisher, which simply forwards all stream elements from its upstream
+121   * to its downstream. It must be able to internally buffer the given number of elements.
+122   *
+123   * @param bufferSize number of elements the processor is required to be able to buffer.
+124   */
+125  public abstract Processor<T, T> createIdentityProcessor(int bufferSize);
+126
+127  /**
+128   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+129   *
+130   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+131   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+132   *
+133   * If you ignore these additional tests, return {@code null} from this method.
+134   */
+135  public abstract Publisher<T> createFailedPublisher();
+136
+137  /**
+138   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+139   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+140   *
+141   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+142   *
+143   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+144   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+145   */
+146  public long maxElementsFromPublisher() {
+147    return Long.MAX_VALUE - 1;
+148  }
+149
+150  /**
+151   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+152   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+153   * recursive calls to exceed the number returned by this method.
+154   *
+155   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+156   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+157   */
+158  public long boundedDepthOfOnNextAndRequestRecursion() {
+159    return 1;
+160  }
+161
+162  /**
+163   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+164   * Such tests MAY sometimes fail even though the impl
+165   */
+166  public boolean skipStochasticTests() {
+167    return false;
+168  }
+169
+170  /**
+171   * Describes the tested implementation in terms of how many subscribers they can support.
+172   * Some tests require the {@code Publisher} under test to support multiple Subscribers,
+173   * yet the spec does not require all publishers to be able to do so, thus – if an implementation
+174   * supports only a limited number of subscribers (e.g. only 1 subscriber, also known as "no fanout")
+175   * you MUST return that number from this method by overriding it.
+176   */
+177  public long maxSupportedSubscribers() {
+178      return Long.MAX_VALUE;
+179  }
+180
+181  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+182
+183  @BeforeMethod
+184  public void setUp() throws Exception {
+185    publisherVerification.setUp();
+186    subscriberVerification.setUp();
+187  }
+188
+189  ////////////////////// PUBLISHER RULES VERIFICATION ///////////////////////////
+190
+191  // A Processor
+192  //   must obey all Publisher rules on its publishing side
+193  public Publisher<T> createPublisher(long elements) {
+194    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+195    final Publisher<T> pub = createHelperPublisher(elements);
+196    pub.subscribe(processor);
+197    return processor; // we run the PublisherVerification against this
+198  }
+199
+200  @Override @Test
+201  public void required_validate_maxElementsFromPublisher() throws Exception {
+202    publisherVerification.required_validate_maxElementsFromPublisher();
+203  }
+204
+205  @Override @Test
+206  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+207    publisherVerification.required_validate_boundedDepthOfOnNextAndRequestRecursion();
+208  }
+209
+210  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" PUBLISHER //////////////////////
+211  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+212
+213  @Test
+214  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+215    publisherVerification.required_createPublisher1MustProduceAStreamOfExactly1Element();
+216  }
+217
+218  @Test
+219  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+220    publisherVerification.required_createPublisher3MustProduceAStreamOfExactly3Elements();
+221  }
+222
+223  @Override @Test
+224  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+225    publisherVerification.required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements();
+226  }
+227
+228  @Override @Test
+229  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+230    publisherVerification.required_spec102_maySignalLessThanRequestedAndTerminateSubscription();
+231  }
+232
+233  @Override @Test
+234  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+235    publisherVerification.stochastic_spec103_mustSignalOnMethodsSequentially();
+236  }
+237
+238  @Override @Test
+239  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+240    publisherVerification.optional_spec104_mustSignalOnErrorWhenFails();
+241  }
+242
+243  @Override @Test
+244  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+245    publisherVerification.required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates();
+246  }
+247
+248  @Override @Test
+249  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+250    publisherVerification.optional_spec105_emptyStreamMustTerminateBySignallingOnComplete();
+251  }
+252
+253  @Override @Test
+254  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+255    publisherVerification.untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled();
+256  }
+257
+258  @Override @Test
+259  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+260    publisherVerification.required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled();
+261  }
+262
+263  @Override @Test
+264  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+265    publisherVerification.untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled();
+266  }
+267
+268  @Override @Test
+269  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+270    publisherVerification.untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals();
+271  }
+272
+273  @Override @Test
+274  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+275    publisherVerification.untested_spec109_subscribeShouldNotThrowNonFatalThrowable();
+276  }
+277
+278  @Override @Test
+279  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+280    publisherVerification.required_spec109_subscribeThrowNPEOnNullSubscriber();
+281  }
+282
+283  @Override @Test
+284  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+285    publisherVerification.required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe();
+286  }
+287
+288  @Override @Test
+289  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+290    publisherVerification.required_spec109_mustIssueOnSubscribeForNonNullSubscriber();
+291  }
+292
+293  @Override @Test
+294  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+295    publisherVerification.untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice();
+296  }
+297
+298  @Override @Test
+299  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+300    publisherVerification.optional_spec111_maySupportMultiSubscribe();
+301  }
+302
+303  @Override @Test
+304  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+305    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne();
+306  }
+307
+308  @Override @Test
+309  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+310    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront();
+311  }
+312
+313  @Override @Test
+314  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+315    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected();
+316  }
+317
+318  @Override @Test
+319  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+320    publisherVerification.required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe();
+321  }
+322
+323  @Override @Test
+324  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+325    publisherVerification.required_spec303_mustNotAllowUnboundedRecursion();
+326  }
+327
+328  @Override @Test
+329  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+330    publisherVerification.untested_spec304_requestShouldNotPerformHeavyComputations();
+331  }
+332
+333  @Override @Test
+334  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() throws Exception {
+335    publisherVerification.untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation();
+336  }
+337
+338  @Override @Test
+339  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+340    publisherVerification.required_spec306_afterSubscriptionIsCancelledRequestMustBeNops();
+341  }
+342
+343  @Override @Test
+344  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+345    publisherVerification.required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops();
+346  }
+347
+348  @Override @Test
+349  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+350    publisherVerification.required_spec309_requestZeroMustSignalIllegalArgumentException();
+351  }
+352
+353  @Override @Test
+354  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+355    publisherVerification.required_spec309_requestNegativeNumberMustSignalIllegalArgumentException();
+356  }
+357
+358  @Override @Test
+359  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+360    publisherVerification.required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling();
+361  }
+362
+363  @Override @Test
+364  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+365    publisherVerification.required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber();
+366  }
+367
+368  @Override @Test
+369  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+370    publisherVerification.required_spec317_mustSupportAPendingElementCountUpToLongMaxValue();
+371  }
+372
+373  @Override @Test
+374  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+375    publisherVerification.required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue();
+376  }
+377
+378  @Override @Test
+379  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+380    publisherVerification.required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue();
+381  }
+382
+383  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.4
+384  // for multiple subscribers
+385  @Test
+386  public void required_spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError() throws Throwable {
+387    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+388      @Override
+389      public TestSetup apply(Long aLong) throws Throwable {
+390        return new TestSetup(env, processorBufferSize) {{
+391          final ManualSubscriberWithErrorCollection<T> sub1 = new ManualSubscriberWithErrorCollection<T>(env);
+392          env.subscribe(processor, sub1);
+393
+394          final ManualSubscriberWithErrorCollection<T> sub2 = new ManualSubscriberWithErrorCollection<T>(env);
+395          env.subscribe(processor, sub2);
+396
+397          sub1.request(1);
+398          expectRequest();
+399          final T x = sendNextTFromUpstream();
+400          expectNextElement(sub1, x);
+401          sub1.request(1);
+402
+403          // sub1 has received one element, and has one demand pending
+404          // sub2 has not yet requested anything
+405
+406          final Exception ex = new RuntimeException("Test exception");
+407          sendError(ex);
+408          sub1.expectError(ex);
+409          sub2.expectError(ex);
+410
+411          env.verifyNoAsyncErrorsNoDelay();
+412        }};
+413      }
+414    });
+415  }
+416
+417  ////////////////////// SUBSCRIBER RULES VERIFICATION ///////////////////////////
+418  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+419
+420  // A Processor
+421  //   must obey all Subscriber rules on its consuming side
+422  public Subscriber<T> createSubscriber(final SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T> probe) {
+423    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+424    processor.subscribe(
+425        new Subscriber<T>() {
+426          private final Promise<Subscription> subs = new Promise<Subscription>(env);
+427
+428          @Override
+429          public void onSubscribe(final Subscription subscription) {
+430            env.debug(String.format("whiteboxSubscriber::onSubscribe(%s)", subscription));
+431            if (subs.isCompleted()) subscription.cancel(); // the Probe must also pass subscriber verification
+432
+433            probe.registerOnSubscribe(new SubscriberWhiteboxVerification.SubscriberPuppet() {
+434
+435              @Override
+436              public void triggerRequest(long elements) {
+437                subscription.request(elements);
+438              }
+439
+440              @Override
+441              public void signalCancel() {
+442                subscription.cancel();
+443              }
+444            });
+445          }
+446
+447          @Override
+448          public void onNext(T element) {
+449            env.debug(String.format("whiteboxSubscriber::onNext(%s)", element));
+450            probe.registerOnNext(element);
+451          }
+452
+453          @Override
+454          public void onComplete() {
+455            env.debug("whiteboxSubscriber::onComplete()");
+456            probe.registerOnComplete();
+457          }
+458
+459          @Override
+460          public void onError(Throwable cause) {
+461            env.debug(String.format("whiteboxSubscriber::onError(%s)", cause));
+462            probe.registerOnError(cause);
+463          }
+464        });
+465
+466    return processor; // we run the SubscriberVerification against this
+467  }
+468
+469  ////////////////////// OTHER RULE VERIFICATION ///////////////////////////
+470
+471  // A Processor
+472  //   must immediately pass on `onError` events received from its upstream to its downstream
+473  @Test
+474  public void mustImmediatelyPassOnOnErrorEventsReceivedFromItsUpstreamToItsDownstream() throws Exception {
+475    new TestSetup(env, processorBufferSize) {{
+476      final ManualSubscriberWithErrorCollection<T> sub = new ManualSubscriberWithErrorCollection<T>(env);
+477      env.subscribe(processor, sub);
+478
+479      final Exception ex = new RuntimeException("Test exception");
+480      sendError(ex);
+481      sub.expectError(ex); // "immediately", i.e. without a preceding request
+482
+483      env.verifyNoAsyncErrorsNoDelay();
+484    }};
+485  }
+486
+487  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" SUBSCRIBER //////////////////////
+488  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+489
+490  @Test
+491  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+492    subscriberVerification.required_exerciseWhiteboxHappyPath();
+493  }
+494
+495  @Override @Test
+496  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+497    subscriberVerification.required_spec201_mustSignalDemandViaSubscriptionRequest();
+498  }
+499
+500  @Override @Test
+501  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+502    subscriberVerification.untested_spec202_shouldAsynchronouslyDispatch();
+503  }
+504
+505  @Override @Test
+506  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+507    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete();
+508  }
+509
+510  @Override @Test
+511  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+512    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError();
+513  }
+514
+515  @Override @Test
+516  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+517    subscriberVerification.untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError();
+518  }
+519
+520  @Override @Test
+521  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+522    subscriberVerification.required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal();
+523  }
+524
+525  @Override @Test
+526  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+527    subscriberVerification.untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid();
+528  }
+529
+530  @Override @Test
+531  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+532    subscriberVerification.untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization();
+533  }
+534
+535  @Override @Test
+536  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+537    subscriberVerification.required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel();
+538  }
+539
+540  @Override @Test
+541  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+542    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall();
+543  }
+544
+545  @Override @Test
+546  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+547    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall();
+548  }
+549
+550  @Override @Test
+551  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+552    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall();
+553  }
+554
+555  @Override @Test
+556  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+557    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall();
+558  }
+559
+560  @Override @Test
+561  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+562    subscriberVerification.untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents();
+563  }
+564
+565  @Override @Test
+566  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+567    subscriberVerification.untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation();
+568  }
+569
+570  @Override @Test
+571  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+572    subscriberVerification.untested_spec213_failingOnSignalInvocation();
+573  }
+574
+575  @Override @Test
+576  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+577    subscriberVerification.required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull();
+578  }
+579  @Override @Test
+580  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+581    subscriberVerification.required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull();
+582  }
+583  @Override @Test
+584  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+585    subscriberVerification.required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull();
+586  }
+587
+588  @Override @Test
+589  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+590    subscriberVerification.untested_spec301_mustNotBeCalledOutsideSubscriberContext();
+591  }
+592
+593  @Override @Test
+594  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+595    subscriberVerification.required_spec308_requestMustRegisterGivenNumberElementsToBeProduced();
+596  }
+597
+598  @Override @Test
+599  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+600    subscriberVerification.untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber();
+601  }
+602
+603  @Override @Test
+604  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+605    subscriberVerification.untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError();
+606  }
+607
+608  @Override @Test
+609  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+610    subscriberVerification.untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists();
+611  }
+612
+613  @Override @Test
+614  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+615    subscriberVerification.untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError();
+616  }
+617
+618  @Override @Test
+619  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+620    subscriberVerification.untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber();
+621  }
+622
+623  /////////////////////// ADDITIONAL "COROLLARY" TESTS //////////////////////
+624
+625  // A Processor
+626  //   must trigger `requestFromUpstream` for elements that have been requested 'long ago'
+627  @Test
+628  public void required_mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo() throws Throwable {
+629    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+630      @Override
+631      public TestSetup apply(Long subscribers) throws Throwable {
+632        return new TestSetup(env, processorBufferSize) {{
+633          ManualSubscriber<T> sub1 = newSubscriber();
+634          sub1.request(20);
+635
+636          long totalRequests = expectRequest();
+637          final T x = sendNextTFromUpstream();
+638          expectNextElement(sub1, x);
+639
+640          if (totalRequests == 1) {
+641            totalRequests += expectRequest();
+642          }
+643          final T y = sendNextTFromUpstream();
+644          expectNextElement(sub1, y);
+645
+646          if (totalRequests == 2) {
+647            totalRequests += expectRequest();
+648          }
+649
+650          final ManualSubscriber<T> sub2 = newSubscriber();
+651
+652          // sub1 now has 18 pending
+653          // sub2 has 0 pending
+654
+655          final T z = sendNextTFromUpstream();
+656          expectNextElement(sub1, z);
+657          sub2.expectNone(); // since sub2 hasn't requested anything yet
+658
+659          sub2.request(1);
+660          expectNextElement(sub2, z);
+661
+662          if (totalRequests == 3) {
+663            expectRequest();
+664          }
+665
+666          // to avoid error messages during test harness shutdown
+667          sendCompletion();
+668          sub1.expectCompletion(env.defaultTimeoutMillis());
+669          sub2.expectCompletion(env.defaultTimeoutMillis());
+670
+671          env.verifyNoAsyncErrorsNoDelay();
+672        }};
+673      }
+674    });
+675  }
+676
+677  /////////////////////// TEST INFRASTRUCTURE //////////////////////
+678
+679  public void notVerified() {
+680    publisherVerification.notVerified();
+681  }
+682
+683  public void notVerified(String message) {
+684    publisherVerification.notVerified(message);
+685  }
+686
+687  /**
+688   * Test for feature that REQUIRES multiple subscribers to be supported by Publisher.
+689   */
+690  public void optionalMultipleSubscribersTest(long requiredSubscribersSupport, Function<Long, TestSetup> body) throws Throwable {
+691    if (requiredSubscribersSupport > maxSupportedSubscribers())
+692      notVerified(String.format("The Publisher under test only supports %d subscribers, while this test requires at least %d to run.",
+693                                maxSupportedSubscribers(), requiredSubscribersSupport));
+694    else body.apply(requiredSubscribersSupport);
+695  }
+696
+697  public abstract class TestSetup extends ManualPublisher<T> {
+698    final private ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+699    private Set<T> seenTees = new HashSet<T>();
+700
+701    final Processor<T, T> processor;
+702
+703    public TestSetup(TestEnvironment env, int testBufferSize) throws InterruptedException {
+704      super(env);
+705      tees = env.newManualSubscriber(createHelperPublisher(Long.MAX_VALUE));
+706      processor = createIdentityProcessor(testBufferSize);
+707      subscribe(processor);
+708    }
+709
+710    public ManualSubscriber<T> newSubscriber() throws InterruptedException {
+711      return env.newManualSubscriber(processor);
+712    }
+713
+714    public T nextT() throws InterruptedException {
+715      final T t = tees.requestNextElement();
+716      if (seenTees.contains(t)) {
+717        env.flop(String.format("Helper publisher illegally produced the same element %s twice", t));
+718      }
+719      seenTees.add(t);
+720      return t;
+721    }
+722
+723    public void expectNextElement(ManualSubscriber<T> sub, T expected) throws InterruptedException {
+724      final T elem = sub.nextElement(String.format("timeout while awaiting %s", expected));
+725      if (!elem.equals(expected)) {
+726        env.flop(String.format("Received `onNext(%s)` on downstream but expected `onNext(%s)`", elem, expected));
+727      }
+728    }
+729
+730    public T sendNextTFromUpstream() throws InterruptedException {
+731      final T x = nextT();
+732      sendNext(x);
+733      return x;
+734    }
+735  }
+736
+737  public class ManualSubscriberWithErrorCollection<A> extends ManualSubscriberWithSubscriptionSupport<A> {
+738    Promise<Throwable> error;
+739
+740    public ManualSubscriberWithErrorCollection(TestEnvironment env) {
+741      super(env);
+742      error = new Promise<Throwable>(env);
+743    }
+744
+745    @Override
+746    public void onError(Throwable cause) {
+747      error.complete(cause);
+748    }
+749
+750    public void expectError(Throwable cause) throws InterruptedException {
+751      expectError(cause, env.defaultTimeoutMillis());
+752    }
+753
+754    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+755    public void expectError(Throwable cause, long timeoutMillis) throws InterruptedException {
+756      error.expectCompletion(timeoutMillis, "Did not receive expected error on downstream");
+757      if (!cause.equals(error.value())) {
+758        env.flop(String.format("Expected error %s but got %s", cause, error.value()));
+759      }
+760    }
+761  }
+762}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.html new file mode 100644 index 0000000..869e3e1 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/IdentityProcessorVerification.html @@ -0,0 +1,834 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Processor;
+004import org.reactivestreams.Publisher;
+005import org.reactivestreams.Subscriber;
+006import org.reactivestreams.Subscription;
+007import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+008import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+009import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+010import org.reactivestreams.tck.TestEnvironment.Promise;
+011import org.reactivestreams.tck.support.Function;
+012import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+013import org.reactivestreams.tck.support.PublisherVerificationRules;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.util.HashSet;
+018import java.util.Set;
+019
+020public abstract class IdentityProcessorVerification<T> extends WithHelperPublisher<T>
+021  implements SubscriberWhiteboxVerificationRules, PublisherVerificationRules {
+022
+023  private final TestEnvironment env;
+024
+025  ////////////////////// DELEGATED TO SPECS //////////////////////
+026
+027  // for delegating tests
+028  private final SubscriberWhiteboxVerification<T> subscriberVerification;
+029
+030  // for delegating tests
+031  private final PublisherVerification<T> publisherVerification;
+032
+033  ////////////////// END OF DELEGATED TO SPECS //////////////////
+034
+035  // number of elements the processor under test must be able ot buffer,
+036  // without dropping elements. Defaults to `TestEnvironment.TEST_BUFFER_SIZE`.
+037  private final int processorBufferSize;
+038
+039  /**
+040   * Test class must specify the expected time it takes for the publisher to
+041   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+042   *
+043   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+044   */
+045  @SuppressWarnings("unused")
+046  public IdentityProcessorVerification(final TestEnvironment env) {
+047    this(env, PublisherVerification.envPublisherReferenceGCTimeoutMillis(), TestEnvironment.TEST_BUFFER_SIZE);
+048  }
+049
+050  /**
+051   * Test class must specify the expected time it takes for the publisher to
+052   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+053   *
+054   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+055   *
+056   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+057   */
+058  @SuppressWarnings("unused")
+059  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+060    this(env, publisherReferenceGCTimeoutMillis, TestEnvironment.TEST_BUFFER_SIZE);
+061  }
+062
+063  /**
+064   * Test class must specify the expected time it takes for the publisher to
+065   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+066   *
+067   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+068   * @param processorBufferSize            number of elements the processor is required to be able to buffer.
+069   */
+070  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis, int processorBufferSize) {
+071    this.env = env;
+072    this.processorBufferSize = processorBufferSize;
+073
+074    this.subscriberVerification = new SubscriberWhiteboxVerification<T>(env) {
+075      @Override
+076      public Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe) {
+077        return IdentityProcessorVerification.this.createSubscriber(probe);
+078      }
+079
+080      @Override public T createElement(int element) {
+081        return IdentityProcessorVerification.this.createElement(element);
+082      }
+083
+084      @Override
+085      public Publisher<T> createHelperPublisher(long elements) {
+086        return IdentityProcessorVerification.this.createHelperPublisher(elements);
+087      }
+088    };
+089
+090    publisherVerification = new PublisherVerification<T>(env, publisherReferenceGCTimeoutMillis) {
+091      @Override
+092      public Publisher<T> createPublisher(long elements) {
+093        return IdentityProcessorVerification.this.createPublisher(elements);
+094      }
+095
+096      @Override
+097      public Publisher<T> createFailedPublisher() {
+098        return IdentityProcessorVerification.this.createFailedPublisher();
+099      }
+100
+101      @Override
+102      public long maxElementsFromPublisher() {
+103        return IdentityProcessorVerification.this.maxElementsFromPublisher();
+104      }
+105
+106      @Override
+107      public long boundedDepthOfOnNextAndRequestRecursion() {
+108        return IdentityProcessorVerification.this.boundedDepthOfOnNextAndRequestRecursion();
+109      }
+110
+111      @Override
+112      public boolean skipStochasticTests() {
+113        return IdentityProcessorVerification.this.skipStochasticTests();
+114      }
+115    };
+116  }
+117
+118  /**
+119   * This is the main method you must implement in your test incarnation.
+120   * It must create a Publisher, which simply forwards all stream elements from its upstream
+121   * to its downstream. It must be able to internally buffer the given number of elements.
+122   *
+123   * @param bufferSize number of elements the processor is required to be able to buffer.
+124   */
+125  public abstract Processor<T, T> createIdentityProcessor(int bufferSize);
+126
+127  /**
+128   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+129   *
+130   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+131   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+132   *
+133   * If you ignore these additional tests, return {@code null} from this method.
+134   */
+135  public abstract Publisher<T> createFailedPublisher();
+136
+137  /**
+138   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+139   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+140   *
+141   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+142   *
+143   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+144   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+145   */
+146  public long maxElementsFromPublisher() {
+147    return Long.MAX_VALUE - 1;
+148  }
+149
+150  /**
+151   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+152   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+153   * recursive calls to exceed the number returned by this method.
+154   *
+155   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+156   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+157   */
+158  public long boundedDepthOfOnNextAndRequestRecursion() {
+159    return 1;
+160  }
+161
+162  /**
+163   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+164   * Such tests MAY sometimes fail even though the impl
+165   */
+166  public boolean skipStochasticTests() {
+167    return false;
+168  }
+169
+170  /**
+171   * Describes the tested implementation in terms of how many subscribers they can support.
+172   * Some tests require the {@code Publisher} under test to support multiple Subscribers,
+173   * yet the spec does not require all publishers to be able to do so, thus – if an implementation
+174   * supports only a limited number of subscribers (e.g. only 1 subscriber, also known as "no fanout")
+175   * you MUST return that number from this method by overriding it.
+176   */
+177  public long maxSupportedSubscribers() {
+178      return Long.MAX_VALUE;
+179  }
+180
+181  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+182
+183  @BeforeMethod
+184  public void setUp() throws Exception {
+185    publisherVerification.setUp();
+186    subscriberVerification.setUp();
+187  }
+188
+189  ////////////////////// PUBLISHER RULES VERIFICATION ///////////////////////////
+190
+191  // A Processor
+192  //   must obey all Publisher rules on its publishing side
+193  public Publisher<T> createPublisher(long elements) {
+194    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+195    final Publisher<T> pub = createHelperPublisher(elements);
+196    pub.subscribe(processor);
+197    return processor; // we run the PublisherVerification against this
+198  }
+199
+200  @Override @Test
+201  public void required_validate_maxElementsFromPublisher() throws Exception {
+202    publisherVerification.required_validate_maxElementsFromPublisher();
+203  }
+204
+205  @Override @Test
+206  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+207    publisherVerification.required_validate_boundedDepthOfOnNextAndRequestRecursion();
+208  }
+209
+210  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" PUBLISHER //////////////////////
+211  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+212
+213  @Test
+214  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+215    publisherVerification.required_createPublisher1MustProduceAStreamOfExactly1Element();
+216  }
+217
+218  @Test
+219  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+220    publisherVerification.required_createPublisher3MustProduceAStreamOfExactly3Elements();
+221  }
+222
+223  @Override @Test
+224  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+225    publisherVerification.required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements();
+226  }
+227
+228  @Override @Test
+229  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+230    publisherVerification.required_spec102_maySignalLessThanRequestedAndTerminateSubscription();
+231  }
+232
+233  @Override @Test
+234  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+235    publisherVerification.stochastic_spec103_mustSignalOnMethodsSequentially();
+236  }
+237
+238  @Override @Test
+239  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+240    publisherVerification.optional_spec104_mustSignalOnErrorWhenFails();
+241  }
+242
+243  @Override @Test
+244  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+245    publisherVerification.required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates();
+246  }
+247
+248  @Override @Test
+249  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+250    publisherVerification.optional_spec105_emptyStreamMustTerminateBySignallingOnComplete();
+251  }
+252
+253  @Override @Test
+254  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+255    publisherVerification.untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled();
+256  }
+257
+258  @Override @Test
+259  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+260    publisherVerification.required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled();
+261  }
+262
+263  @Override @Test
+264  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+265    publisherVerification.untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled();
+266  }
+267
+268  @Override @Test
+269  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+270    publisherVerification.untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals();
+271  }
+272
+273  @Override @Test
+274  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+275    publisherVerification.untested_spec109_subscribeShouldNotThrowNonFatalThrowable();
+276  }
+277
+278  @Override @Test
+279  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+280    publisherVerification.required_spec109_subscribeThrowNPEOnNullSubscriber();
+281  }
+282
+283  @Override @Test
+284  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+285    publisherVerification.required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe();
+286  }
+287
+288  @Override @Test
+289  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+290    publisherVerification.required_spec109_mustIssueOnSubscribeForNonNullSubscriber();
+291  }
+292
+293  @Override @Test
+294  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+295    publisherVerification.untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice();
+296  }
+297
+298  @Override @Test
+299  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+300    publisherVerification.optional_spec111_maySupportMultiSubscribe();
+301  }
+302
+303  @Override @Test
+304  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+305    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne();
+306  }
+307
+308  @Override @Test
+309  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+310    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront();
+311  }
+312
+313  @Override @Test
+314  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+315    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected();
+316  }
+317
+318  @Override @Test
+319  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+320    publisherVerification.required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe();
+321  }
+322
+323  @Override @Test
+324  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+325    publisherVerification.required_spec303_mustNotAllowUnboundedRecursion();
+326  }
+327
+328  @Override @Test
+329  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+330    publisherVerification.untested_spec304_requestShouldNotPerformHeavyComputations();
+331  }
+332
+333  @Override @Test
+334  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() throws Exception {
+335    publisherVerification.untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation();
+336  }
+337
+338  @Override @Test
+339  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+340    publisherVerification.required_spec306_afterSubscriptionIsCancelledRequestMustBeNops();
+341  }
+342
+343  @Override @Test
+344  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+345    publisherVerification.required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops();
+346  }
+347
+348  @Override @Test
+349  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+350    publisherVerification.required_spec309_requestZeroMustSignalIllegalArgumentException();
+351  }
+352
+353  @Override @Test
+354  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+355    publisherVerification.required_spec309_requestNegativeNumberMustSignalIllegalArgumentException();
+356  }
+357
+358  @Override @Test
+359  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+360    publisherVerification.required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling();
+361  }
+362
+363  @Override @Test
+364  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+365    publisherVerification.required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber();
+366  }
+367
+368  @Override @Test
+369  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+370    publisherVerification.required_spec317_mustSupportAPendingElementCountUpToLongMaxValue();
+371  }
+372
+373  @Override @Test
+374  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+375    publisherVerification.required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue();
+376  }
+377
+378  @Override @Test
+379  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+380    publisherVerification.required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue();
+381  }
+382
+383  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.4
+384  // for multiple subscribers
+385  @Test
+386  public void required_spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError() throws Throwable {
+387    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+388      @Override
+389      public TestSetup apply(Long aLong) throws Throwable {
+390        return new TestSetup(env, processorBufferSize) {{
+391          final ManualSubscriberWithErrorCollection<T> sub1 = new ManualSubscriberWithErrorCollection<T>(env);
+392          env.subscribe(processor, sub1);
+393
+394          final ManualSubscriberWithErrorCollection<T> sub2 = new ManualSubscriberWithErrorCollection<T>(env);
+395          env.subscribe(processor, sub2);
+396
+397          sub1.request(1);
+398          expectRequest();
+399          final T x = sendNextTFromUpstream();
+400          expectNextElement(sub1, x);
+401          sub1.request(1);
+402
+403          // sub1 has received one element, and has one demand pending
+404          // sub2 has not yet requested anything
+405
+406          final Exception ex = new RuntimeException("Test exception");
+407          sendError(ex);
+408          sub1.expectError(ex);
+409          sub2.expectError(ex);
+410
+411          env.verifyNoAsyncErrorsNoDelay();
+412        }};
+413      }
+414    });
+415  }
+416
+417  ////////////////////// SUBSCRIBER RULES VERIFICATION ///////////////////////////
+418  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+419
+420  // A Processor
+421  //   must obey all Subscriber rules on its consuming side
+422  public Subscriber<T> createSubscriber(final SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T> probe) {
+423    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+424    processor.subscribe(
+425        new Subscriber<T>() {
+426          private final Promise<Subscription> subs = new Promise<Subscription>(env);
+427
+428          @Override
+429          public void onSubscribe(final Subscription subscription) {
+430            env.debug(String.format("whiteboxSubscriber::onSubscribe(%s)", subscription));
+431            if (subs.isCompleted()) subscription.cancel(); // the Probe must also pass subscriber verification
+432
+433            probe.registerOnSubscribe(new SubscriberWhiteboxVerification.SubscriberPuppet() {
+434
+435              @Override
+436              public void triggerRequest(long elements) {
+437                subscription.request(elements);
+438              }
+439
+440              @Override
+441              public void signalCancel() {
+442                subscription.cancel();
+443              }
+444            });
+445          }
+446
+447          @Override
+448          public void onNext(T element) {
+449            env.debug(String.format("whiteboxSubscriber::onNext(%s)", element));
+450            probe.registerOnNext(element);
+451          }
+452
+453          @Override
+454          public void onComplete() {
+455            env.debug("whiteboxSubscriber::onComplete()");
+456            probe.registerOnComplete();
+457          }
+458
+459          @Override
+460          public void onError(Throwable cause) {
+461            env.debug(String.format("whiteboxSubscriber::onError(%s)", cause));
+462            probe.registerOnError(cause);
+463          }
+464        });
+465
+466    return processor; // we run the SubscriberVerification against this
+467  }
+468
+469  ////////////////////// OTHER RULE VERIFICATION ///////////////////////////
+470
+471  // A Processor
+472  //   must immediately pass on `onError` events received from its upstream to its downstream
+473  @Test
+474  public void mustImmediatelyPassOnOnErrorEventsReceivedFromItsUpstreamToItsDownstream() throws Exception {
+475    new TestSetup(env, processorBufferSize) {{
+476      final ManualSubscriberWithErrorCollection<T> sub = new ManualSubscriberWithErrorCollection<T>(env);
+477      env.subscribe(processor, sub);
+478
+479      final Exception ex = new RuntimeException("Test exception");
+480      sendError(ex);
+481      sub.expectError(ex); // "immediately", i.e. without a preceding request
+482
+483      env.verifyNoAsyncErrorsNoDelay();
+484    }};
+485  }
+486
+487  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" SUBSCRIBER //////////////////////
+488  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+489
+490  @Test
+491  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+492    subscriberVerification.required_exerciseWhiteboxHappyPath();
+493  }
+494
+495  @Override @Test
+496  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+497    subscriberVerification.required_spec201_mustSignalDemandViaSubscriptionRequest();
+498  }
+499
+500  @Override @Test
+501  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+502    subscriberVerification.untested_spec202_shouldAsynchronouslyDispatch();
+503  }
+504
+505  @Override @Test
+506  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+507    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete();
+508  }
+509
+510  @Override @Test
+511  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+512    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError();
+513  }
+514
+515  @Override @Test
+516  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+517    subscriberVerification.untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError();
+518  }
+519
+520  @Override @Test
+521  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+522    subscriberVerification.required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal();
+523  }
+524
+525  @Override @Test
+526  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+527    subscriberVerification.untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid();
+528  }
+529
+530  @Override @Test
+531  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+532    subscriberVerification.untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization();
+533  }
+534
+535  @Override @Test
+536  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+537    subscriberVerification.required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel();
+538  }
+539
+540  @Override @Test
+541  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+542    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall();
+543  }
+544
+545  @Override @Test
+546  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+547    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall();
+548  }
+549
+550  @Override @Test
+551  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+552    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall();
+553  }
+554
+555  @Override @Test
+556  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+557    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall();
+558  }
+559
+560  @Override @Test
+561  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+562    subscriberVerification.untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents();
+563  }
+564
+565  @Override @Test
+566  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+567    subscriberVerification.untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation();
+568  }
+569
+570  @Override @Test
+571  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+572    subscriberVerification.untested_spec213_failingOnSignalInvocation();
+573  }
+574
+575  @Override @Test
+576  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+577    subscriberVerification.required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull();
+578  }
+579  @Override @Test
+580  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+581    subscriberVerification.required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull();
+582  }
+583  @Override @Test
+584  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+585    subscriberVerification.required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull();
+586  }
+587
+588  @Override @Test
+589  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+590    subscriberVerification.untested_spec301_mustNotBeCalledOutsideSubscriberContext();
+591  }
+592
+593  @Override @Test
+594  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+595    subscriberVerification.required_spec308_requestMustRegisterGivenNumberElementsToBeProduced();
+596  }
+597
+598  @Override @Test
+599  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+600    subscriberVerification.untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber();
+601  }
+602
+603  @Override @Test
+604  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+605    subscriberVerification.untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError();
+606  }
+607
+608  @Override @Test
+609  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+610    subscriberVerification.untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists();
+611  }
+612
+613  @Override @Test
+614  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+615    subscriberVerification.untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError();
+616  }
+617
+618  @Override @Test
+619  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+620    subscriberVerification.untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber();
+621  }
+622
+623  /////////////////////// ADDITIONAL "COROLLARY" TESTS //////////////////////
+624
+625  // A Processor
+626  //   must trigger `requestFromUpstream` for elements that have been requested 'long ago'
+627  @Test
+628  public void required_mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo() throws Throwable {
+629    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+630      @Override
+631      public TestSetup apply(Long subscribers) throws Throwable {
+632        return new TestSetup(env, processorBufferSize) {{
+633          ManualSubscriber<T> sub1 = newSubscriber();
+634          sub1.request(20);
+635
+636          long totalRequests = expectRequest();
+637          final T x = sendNextTFromUpstream();
+638          expectNextElement(sub1, x);
+639
+640          if (totalRequests == 1) {
+641            totalRequests += expectRequest();
+642          }
+643          final T y = sendNextTFromUpstream();
+644          expectNextElement(sub1, y);
+645
+646          if (totalRequests == 2) {
+647            totalRequests += expectRequest();
+648          }
+649
+650          final ManualSubscriber<T> sub2 = newSubscriber();
+651
+652          // sub1 now has 18 pending
+653          // sub2 has 0 pending
+654
+655          final T z = sendNextTFromUpstream();
+656          expectNextElement(sub1, z);
+657          sub2.expectNone(); // since sub2 hasn't requested anything yet
+658
+659          sub2.request(1);
+660          expectNextElement(sub2, z);
+661
+662          if (totalRequests == 3) {
+663            expectRequest();
+664          }
+665
+666          // to avoid error messages during test harness shutdown
+667          sendCompletion();
+668          sub1.expectCompletion(env.defaultTimeoutMillis());
+669          sub2.expectCompletion(env.defaultTimeoutMillis());
+670
+671          env.verifyNoAsyncErrorsNoDelay();
+672        }};
+673      }
+674    });
+675  }
+676
+677  /////////////////////// TEST INFRASTRUCTURE //////////////////////
+678
+679  public void notVerified() {
+680    publisherVerification.notVerified();
+681  }
+682
+683  public void notVerified(String message) {
+684    publisherVerification.notVerified(message);
+685  }
+686
+687  /**
+688   * Test for feature that REQUIRES multiple subscribers to be supported by Publisher.
+689   */
+690  public void optionalMultipleSubscribersTest(long requiredSubscribersSupport, Function<Long, TestSetup> body) throws Throwable {
+691    if (requiredSubscribersSupport > maxSupportedSubscribers())
+692      notVerified(String.format("The Publisher under test only supports %d subscribers, while this test requires at least %d to run.",
+693                                maxSupportedSubscribers(), requiredSubscribersSupport));
+694    else body.apply(requiredSubscribersSupport);
+695  }
+696
+697  public abstract class TestSetup extends ManualPublisher<T> {
+698    final private ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+699    private Set<T> seenTees = new HashSet<T>();
+700
+701    final Processor<T, T> processor;
+702
+703    public TestSetup(TestEnvironment env, int testBufferSize) throws InterruptedException {
+704      super(env);
+705      tees = env.newManualSubscriber(createHelperPublisher(Long.MAX_VALUE));
+706      processor = createIdentityProcessor(testBufferSize);
+707      subscribe(processor);
+708    }
+709
+710    public ManualSubscriber<T> newSubscriber() throws InterruptedException {
+711      return env.newManualSubscriber(processor);
+712    }
+713
+714    public T nextT() throws InterruptedException {
+715      final T t = tees.requestNextElement();
+716      if (seenTees.contains(t)) {
+717        env.flop(String.format("Helper publisher illegally produced the same element %s twice", t));
+718      }
+719      seenTees.add(t);
+720      return t;
+721    }
+722
+723    public void expectNextElement(ManualSubscriber<T> sub, T expected) throws InterruptedException {
+724      final T elem = sub.nextElement(String.format("timeout while awaiting %s", expected));
+725      if (!elem.equals(expected)) {
+726        env.flop(String.format("Received `onNext(%s)` on downstream but expected `onNext(%s)`", elem, expected));
+727      }
+728    }
+729
+730    public T sendNextTFromUpstream() throws InterruptedException {
+731      final T x = nextT();
+732      sendNext(x);
+733      return x;
+734    }
+735  }
+736
+737  public class ManualSubscriberWithErrorCollection<A> extends ManualSubscriberWithSubscriptionSupport<A> {
+738    Promise<Throwable> error;
+739
+740    public ManualSubscriberWithErrorCollection(TestEnvironment env) {
+741      super(env);
+742      error = new Promise<Throwable>(env);
+743    }
+744
+745    @Override
+746    public void onError(Throwable cause) {
+747      error.complete(cause);
+748    }
+749
+750    public void expectError(Throwable cause) throws InterruptedException {
+751      expectError(cause, env.defaultTimeoutMillis());
+752    }
+753
+754    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+755    public void expectError(Throwable cause, long timeoutMillis) throws InterruptedException {
+756      error.expectCompletion(timeoutMillis, "Did not receive expected error on downstream");
+757      if (!cause.equals(error.value())) {
+758        env.flop(String.format("Expected error %s but got %s", cause, error.value()));
+759      }
+760    }
+761  }
+762}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html new file mode 100644 index 0000000..62bc3dc --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.PublisherTestRun.html @@ -0,0 +1,1255 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport;
+007import org.reactivestreams.tck.TestEnvironment.Latch;
+008import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+009import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+010import org.reactivestreams.tck.support.Function;
+011import org.reactivestreams.tck.support.Optional;
+012import org.reactivestreams.tck.support.PublisherVerificationRules;
+013import org.testng.SkipException;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.lang.Override;
+018import java.lang.ref.ReferenceQueue;
+019import java.lang.ref.WeakReference;
+020import java.util.ArrayList;
+021import java.util.Arrays;
+022import java.util.Collections;
+023import java.util.List;
+024import java.util.Random;
+025import java.util.concurrent.atomic.AtomicReference;
+026
+027import static org.testng.Assert.assertEquals;
+028import static org.testng.Assert.assertTrue;
+029
+030/**
+031 * Provides tests for verifying {@code Publisher} specification rules.
+032 *
+033 * @see org.reactivestreams.Publisher
+034 */
+035public abstract class PublisherVerification<T> implements PublisherVerificationRules {
+036
+037  private static final String PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV = "PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS";
+038  private static final long DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS = 300L;
+039
+040  private final TestEnvironment env;
+041
+042  /**
+043   * The amount of time after which a cancelled Subscriber reference should be dropped.
+044   * See Rule 3.13 for details.
+045   */
+046  private final long publisherReferenceGCTimeoutMillis;
+047
+048  /**
+049   * Constructs a new verification class using the given env and configuration.
+050   *
+051   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+052   */
+053  public PublisherVerification(TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+054    this.env = env;
+055    this.publisherReferenceGCTimeoutMillis = publisherReferenceGCTimeoutMillis;
+056  }
+057
+058  /**
+059   * Constructs a new verification class using the given env and configuration.
+060   *
+061   * The value for {@code publisherReferenceGCTimeoutMillis} will be obtained by using {@link PublisherVerification#envPublisherReferenceGCTimeoutMillis()}.
+062   */
+063  public PublisherVerification(TestEnvironment env) {
+064    this.env = env;
+065    this.publisherReferenceGCTimeoutMillis = envPublisherReferenceGCTimeoutMillis();
+066  }
+067
+068  /**
+069   * Tries to parse the env variable {@code PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS} as long and returns the value if present,
+070   * OR its default value ({@link PublisherVerification#DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS}).
+071   *
+072   * This value is used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+073   *
+074   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+075   */
+076  public static long envPublisherReferenceGCTimeoutMillis() {
+077    final String envMillis = System.getenv(PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV);
+078    if (envMillis == null) return DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS;
+079    else try {
+080      return Long.parseLong(envMillis);
+081    } catch(NumberFormatException ex) {
+082      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV, envMillis), ex);
+083    }
+084  }
+085
+086  /**
+087   * This is the main method you must implement in your test incarnation.
+088   * It must create a Publisher for a stream with exactly the given number of elements.
+089   * If `elements` is `Long.MAX_VALUE` the produced stream must be infinite.
+090   */
+091  public abstract Publisher<T> createPublisher(long elements);
+092
+093  /**
+094   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+095   *
+096   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+097   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+098   *
+099   * If you ignore these additional tests, return {@code null} from this method.
+100   */
+101  public abstract Publisher<T> createFailedPublisher();
+102
+103
+104  /**
+105   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+106   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+107   *
+108   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+109   *
+110   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+111   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+112   */
+113  public long maxElementsFromPublisher() {
+114    return Long.MAX_VALUE - 1;
+115  }
+116
+117  /**
+118   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+119   * Such tests MAY sometimes fail even though the impl
+120   */
+121  public boolean skipStochasticTests() {
+122    return false;
+123  }
+124
+125  /**
+126   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+127   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+128   * recursive calls to exceed the number returned by this method.
+129   *
+130   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+131   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+132   */
+133  public long boundedDepthOfOnNextAndRequestRecursion() {
+134    return 1;
+135  }
+136
+137  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+138
+139  @BeforeMethod
+140  public void setUp() throws Exception {
+141    env.clearAsyncErrors();
+142  }
+143
+144  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+145
+146  @Override @Test
+147  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+148    activePublisherTest(1, true, new PublisherTestRun<T>() {
+149      @Override
+150      public void run(Publisher<T> pub) throws InterruptedException {
+151        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+152        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced no elements", pub));
+153        sub.requestEndOfStream();
+154      }
+155
+156      Optional<T> requestNextElementOrEndOfStream(Publisher<T> pub, ManualSubscriber<T> sub) throws InterruptedException {
+157        return sub.requestNextElementOrEndOfStream(String.format("Timeout while waiting for next element from Publisher %s", pub));
+158      }
+159
+160    });
+161  }
+162
+163  @Override @Test
+164  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+165    activePublisherTest(3, true, new PublisherTestRun<T>() {
+166      @Override
+167      public void run(Publisher<T> pub) throws InterruptedException {
+168        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+169        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced no elements", pub));
+170        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced only 1 element", pub));
+171        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced only 2 elements", pub));
+172        sub.requestEndOfStream();
+173      }
+174
+175      Optional<T> requestNextElementOrEndOfStream(Publisher<T> pub, ManualSubscriber<T> sub) throws InterruptedException {
+176        return sub.requestNextElementOrEndOfStream(String.format("Timeout while waiting for next element from Publisher %s", pub));
+177      }
+178
+179    });
+180  }
+181
+182  @Override @Test
+183  public void required_validate_maxElementsFromPublisher() throws Exception {
+184    assertTrue(maxElementsFromPublisher() >= 0, "maxElementsFromPublisher MUST return a number >= 0");
+185  }
+186
+187  @Override @Test
+188  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+189    assertTrue(boundedDepthOfOnNextAndRequestRecursion() >= 1, "boundedDepthOfOnNextAndRequestRecursion must return a number >= 1");
+190  }
+191
+192
+193  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+194
+195  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.1
+196  @Override @Test
+197  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+198    activePublisherTest(5, false, new PublisherTestRun<T>() {
+199      @Override
+200      public void run(Publisher<T> pub) throws InterruptedException {
+201
+202        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+203
+204        sub.expectNone(String.format("Publisher %s produced value before the first `request`: ", pub));
+205        sub.request(1);
+206        sub.nextElement(String.format("Publisher %s produced no element after first `request`", pub));
+207        sub.expectNone(String.format("Publisher %s produced unrequested: ", pub));
+208
+209        sub.request(1);
+210        sub.request(2);
+211        sub.nextElements(3, env.defaultTimeoutMillis(), String.format("Publisher %s produced less than 3 elements after two respective `request` calls", pub));
+212
+213        sub.expectNone(String.format("Publisher %sproduced unrequested ", pub));
+214      }
+215    });
+216  }
+217
+218  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.2
+219  @Override @Test
+220  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+221    final int elements = 3;
+222    final int requested = 10;
+223
+224    activePublisherTest(elements, true, new PublisherTestRun<T>() {
+225      @Override
+226      public void run(Publisher<T> pub) throws Throwable {
+227        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+228        sub.request(requested);
+229        sub.nextElements(elements);
+230        sub.expectCompletion();
+231      }
+232    });
+233  }
+234
+235  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.3
+236  @Override @Test
+237  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+238    final int iterations = 100;
+239    final int elements = 10;
+240
+241    stochasticTest(iterations, new Function<Integer, Void>() {
+242      @Override
+243      public Void apply(final Integer runNumber) throws Throwable {
+244        activePublisherTest(elements, true, new PublisherTestRun<T>() {
+245          @Override
+246          public void run(Publisher<T> pub) throws Throwable {
+247            final Latch completionLatch = new Latch(env);
+248
+249            pub.subscribe(new Subscriber<T>() {
+250              private Subscription subs;
+251              private long gotElements = 0;
+252
+253              private ConcurrentAccessBarrier concurrentAccessBarrier = new ConcurrentAccessBarrier();
+254
+255              /**
+256               * Concept wise very similar to a {@link org.reactivestreams.tck.TestEnvironment.Latch}, serves to protect
+257               * a critical section from concurrent access, with the added benefit of Thread tracking and same-thread-access awareness.
+258               *
+259               * Since a <i>Synchronous</i> Publisher may choose to synchronously (using the same {@link Thread}) call
+260               * {@code onNext} directly from either {@code subscribe} or {@code request} a plain Latch is not enough
+261               * to verify concurrent access safety - one needs to track if the caller is not still using the calling thread
+262               * to enter subsequent critical sections ("nesting" them effectively).
+263               */
+264              final class ConcurrentAccessBarrier {
+265                private AtomicReference<Thread> currentlySignallingThread = new AtomicReference<Thread>(null);
+266                private volatile String previousSignal = null;
+267
+268                public void enterSignal(String signalName) {
+269                  if((!currentlySignallingThread.compareAndSet(null, Thread.currentThread())) && !isSynchronousSignal()) {
+270                    env.flop(String.format(
+271                      "Illegal concurrent access detected (entering critical section)! " +
+272                        "%s emited %s signal, before %s finished its %s signal.",
+273                        Thread.currentThread(), signalName, currentlySignallingThread.get(), previousSignal));
+274                  }
+275                  this.previousSignal = signalName;
+276                }
+277
+278                public void leaveSignal(String signalName) {
+279                  currentlySignallingThread.set(null);
+280                  this.previousSignal = signalName;
+281                }
+282
+283                private boolean isSynchronousSignal() {
+284                  return (previousSignal != null) && Thread.currentThread().equals(currentlySignallingThread.get());
+285                }
+286
+287              }
+288
+289              @Override
+290              public void onSubscribe(Subscription s) {
+291                final String signal = "onSubscribe()";
+292                concurrentAccessBarrier.enterSignal(signal);
+293
+294                subs = s;
+295                subs.request(1);
+296
+297                concurrentAccessBarrier.leaveSignal(signal);
+298              }
+299
+300              @Override
+301              public void onNext(T ignore) {
+302                final String signal = String.format("onNext(%s)", ignore);
+303                concurrentAccessBarrier.enterSignal(signal);
+304
+305                gotElements += 1;
+306                if (gotElements <= elements) // requesting one more than we know are in the stream (some Publishers need this)
+307                  subs.request(1);
+308
+309                concurrentAccessBarrier.leaveSignal(signal);
+310              }
+311
+312              @Override
+313              public void onError(Throwable t) {
+314                final String signal = String.format("onError(%s)", t.getMessage());
+315                concurrentAccessBarrier.enterSignal(signal);
+316
+317                // ignore value
+318
+319                concurrentAccessBarrier.leaveSignal(signal);
+320              }
+321
+322              @Override
+323              public void onComplete() {
+324                final String signal = "onComplete()";
+325                concurrentAccessBarrier.enterSignal(signal);
+326
+327                // entering for completeness
+328
+329                concurrentAccessBarrier.leaveSignal(signal);
+330                completionLatch.close();
+331              }
+332            });
+333
+334            completionLatch.expectClose(elements * env.defaultTimeoutMillis(), "Expected 10 elements to be drained");
+335          }
+336        });
+337        return null;
+338      }
+339    });
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.4
+343  @Override @Test
+344  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+345    try {
+346      whenHasErrorPublisherTest(new PublisherTestRun<T>() {
+347        @Override
+348        public void run(final Publisher<T> pub) throws InterruptedException {
+349          final Latch onErrorlatch = new Latch(env);
+350          final Latch onSubscribeLatch = new Latch(env);
+351          pub.subscribe(new TestEnvironment.TestSubscriber<T>(env) {
+352            @Override
+353            public void onSubscribe(Subscription subs) {
+354              onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+355              onSubscribeLatch.close();
+356            }
+357            @Override
+358            public void onError(Throwable cause) {
+359              onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+360              onErrorlatch.assertOpen(String.format("Error-state Publisher %s called `onError` twice on new Subscriber", pub));
+361              onErrorlatch.close();
+362            }
+363          });
+364
+365          onSubscribeLatch.expectClose("Should have received onSubscribe");
+366          onErrorlatch.expectClose(String.format("Error-state Publisher %s did not call `onError` on new Subscriber", pub));
+367
+368          env.verifyNoAsyncErrors(env.defaultTimeoutMillis());
+369          }
+370      });
+371    } catch (SkipException se) {
+372      throw se;
+373    } catch (Throwable ex) {
+374      // we also want to catch AssertionErrors and anything the publisher may have thrown inside subscribe
+375      // which was wrong of him - he should have signalled on error using onError
+376      throw new RuntimeException(String.format("Publisher threw exception (%s) instead of signalling error via onError!", ex.getMessage()), ex);
+377    }
+378  }
+379
+380  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.5
+381  @Override @Test
+382  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+383    activePublisherTest(3, true, new PublisherTestRun<T>() {
+384      @Override
+385      public void run(Publisher<T> pub) throws Throwable {
+386        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+387        sub.requestNextElement();
+388        sub.requestNextElement();
+389        sub.requestNextElement();
+390        sub.requestEndOfStream();
+391        sub.expectNone();
+392      }
+393    });
+394  }
+395
+396  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.5
+397  @Override @Test
+398  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+399    optionalActivePublisherTest(0, true, new PublisherTestRun<T>() {
+400      @Override
+401      public void run(Publisher<T> pub) throws Throwable {
+402        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+403        sub.request(1);
+404        sub.expectCompletion();
+405        sub.expectNone();
+406      }
+407    });
+408  }
+409
+410  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.6
+411  @Override @Test
+412  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+413    notVerified(); // not really testable without more control over the Publisher
+414  }
+415
+416  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.7
+417  @Override @Test
+418  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+419    activePublisherTest(1, true, new PublisherTestRun<T>() {
+420      @Override
+421      public void run(Publisher<T> pub) throws Throwable {
+422        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+423        sub.request(10);
+424        sub.nextElement();
+425        sub.expectCompletion();
+426
+427        sub.request(10);
+428        sub.expectNone();
+429      }
+430    });
+431  }
+432
+433  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.7
+434  @Override @Test
+435  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+436    notVerified(); // can we meaningfully test this, without more control over the publisher?
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.8
+440  @Override @Test
+441  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+442    notVerified(); // can we meaningfully test this?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+446  @Override @Test
+447  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+448    notVerified(); // can we meaningfully test this?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+452  @Override @Test
+453  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+454    activePublisherTest(0, false, new PublisherTestRun<T>() {
+455      @Override
+456      public void run(Publisher<T> pub) throws Throwable {
+457        try {
+458            pub.subscribe(null);
+459            env.flop("Publisher did not throw a NullPointerException when given a null Subscribe in subscribe");
+460        } catch (NullPointerException ignored) {
+461          // valid behaviour
+462        }
+463        env.verifyNoAsyncErrorsNoDelay();
+464      }
+465    });
+466  }
+467
+468  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+469  @Override @Test
+470  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+471    activePublisherTest(0, false, new PublisherTestRun<T>() {
+472      @Override
+473      public void run(Publisher<T> pub) throws Throwable {
+474        final Latch onSubscribeLatch = new Latch(env);
+475        pub.subscribe(new Subscriber<T>() {
+476          @Override
+477          public void onError(Throwable cause) {
+478            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+479          }
+480
+481          @Override
+482          public void onSubscribe(Subscription subs) {
+483            onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+484            onSubscribeLatch.close();
+485          }
+486
+487          @Override
+488          public void onNext(T elem) {
+489            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onNext always");
+490          }
+491
+492          @Override
+493          public void onComplete() {
+494            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onComplete always");
+495          }
+496        });
+497        onSubscribeLatch.expectClose("Should have received onSubscribe");
+498        env.verifyNoAsyncErrorsNoDelay();
+499      }
+500    });
+501  }
+502
+503  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+504  @Override @Test
+505  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+506    whenHasErrorPublisherTest(new PublisherTestRun<T>() {
+507      @Override
+508      public void run(Publisher<T> pub) throws Throwable {
+509        final Latch onErrorLatch = new Latch(env);
+510        final Latch onSubscribeLatch = new Latch(env);
+511        ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+512          @Override
+513          public void onError(Throwable cause) {
+514            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+515            onErrorLatch.assertOpen("Only one onError call expected");
+516            onErrorLatch.close();
+517          }
+518
+519          @Override
+520          public void onSubscribe(Subscription subs) {
+521            onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+522            onSubscribeLatch.close();
+523          }
+524        };
+525        pub.subscribe(sub);
+526        onSubscribeLatch.expectClose("Should have received onSubscribe");
+527        onErrorLatch.expectClose("Should have received onError");
+528
+529        env.verifyNoAsyncErrorsNoDelay();
+530      }
+531    });
+532  }
+533
+534    // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.10
+535  @Override @Test
+536  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+537    notVerified(); // can we meaningfully test this?
+538  }
+539
+540  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+541  @Override @Test
+542  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+543    optionalActivePublisherTest(1, false, new PublisherTestRun<T>() {
+544      @Override
+545      public void run(Publisher<T> pub) throws Throwable {
+546        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+547        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+548
+549        env.verifyNoAsyncErrors();
+550      }
+551    });
+552  }
+553
+554  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+555  @Override @Test
+556  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+557    optionalActivePublisherTest(5, true, new PublisherTestRun<T>() { // This test is skipped if the publisher is unbounded (never sends onComplete)
+558      @Override
+559      public void run(Publisher<T> pub) throws InterruptedException {
+560        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+561        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+562        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+563
+564        sub1.request(1);
+565        T x1 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+566        sub2.request(2);
+567        List<T> y1 = sub2.nextElements(2, String.format("Publisher %s did not produce the requested 2 elements on 2nd subscriber", pub));
+568        sub1.request(1);
+569        T x2 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+570        sub3.request(3);
+571        List<T> z1 = sub3.nextElements(3, String.format("Publisher %s did not produce the requested 3 elements on 3rd subscriber", pub));
+572        sub3.request(1);
+573        T z2 = sub3.nextElement(String.format("Publisher %s did not produce the requested 1 element on 3rd subscriber", pub));
+574        sub3.request(1);
+575        T z3 = sub3.nextElement(String.format("Publisher %s did not produce the requested 1 element on 3rd subscriber", pub));
+576        sub3.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 3rd subscriber", pub));
+577        sub2.request(3);
+578        List<T> y2 = sub2.nextElements(3, String.format("Publisher %s did not produce the requested 3 elements on 2nd subscriber", pub));
+579        sub2.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 2nd subscriber", pub));
+580        sub1.request(2);
+581        List<T> x3 = sub1.nextElements(2, String.format("Publisher %s did not produce the requested 2 elements on 1st subscriber", pub));
+582        sub1.request(1);
+583        T x4 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+584        sub1.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 1st subscriber", pub));
+585
+586        @SuppressWarnings("unchecked")
+587        List<T> r = new ArrayList<T>(Arrays.asList(x1, x2));
+588        r.addAll(x3);
+589        r.addAll(Collections.singleton(x4));
+590
+591        List<T> check1 = new ArrayList<T>(y1);
+592        check1.addAll(y2);
+593
+594        //noinspection unchecked
+595        List<T> check2 = new ArrayList<T>(z1);
+596        check2.add(z2);
+597        check2.add(z3);
+598
+599        assertEquals(r, check1, String.format("Publisher %s did not produce the same element sequence for subscribers 1 and 2", pub));
+600        assertEquals(r, check2, String.format("Publisher %s did not produce the same element sequence for subscribers 1 and 3", pub));
+601      }
+602    });
+603  }
+604
+605  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+606  @Override @Test
+607  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+608    optionalActivePublisherTest(3, false, new PublisherTestRun<T>() { // This test is skipped if the publisher cannot produce enough elements
+609      @Override
+610      public void run(Publisher<T> pub) throws Throwable {
+611        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+612        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+613        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+614
+615        List<T> received1 = new ArrayList<T>();
+616        List<T> received2 = new ArrayList<T>();
+617        List<T> received3 = new ArrayList<T>();
+618
+619        // if the publisher must touch it's source to notice it's been drained, the OnComplete won't come until we ask for more than it actually contains...
+620        // edgy edge case?
+621        sub1.request(4);
+622        sub2.request(4);
+623        sub3.request(4);
+624
+625        received1.addAll(sub1.nextElements(3));
+626        received2.addAll(sub2.nextElements(3));
+627        received3.addAll(sub3.nextElements(3));
+628
+629        // NOTE: can't check completion, the Publisher may not be able to signal it
+630        //       a similar test *with* completion checking is implemented
+631
+632        assertEquals(received1, received2, String.format("Expected elements to be signaled in the same sequence to 1st and 2nd subscribers"));
+633        assertEquals(received2, received3, String.format("Expected elements to be signaled in the same sequence to 2nd and 3rd subscribers"));
+634      }
+635    });
+636  }
+637
+638  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+639  @Override @Test
+640  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+641    optionalActivePublisherTest(3, true, new PublisherTestRun<T>() { // This test is skipped if the publisher is unbounded (never sends onComplete)
+642      @Override
+643      public void run(Publisher<T> pub) throws Throwable {
+644        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+645        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+646        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+647
+648        List<T> received1 = new ArrayList<T>();
+649        List<T> received2 = new ArrayList<T>();
+650        List<T> received3 = new ArrayList<T>();
+651
+652        // if the publisher must touch it's source to notice it's been drained, the OnComplete won't come until we ask for more than it actually contains...
+653        // edgy edge case?
+654        sub1.request(4);
+655        sub2.request(4);
+656        sub3.request(4);
+657
+658        received1.addAll(sub1.nextElements(3));
+659        received2.addAll(sub2.nextElements(3));
+660        received3.addAll(sub3.nextElements(3));
+661
+662        sub1.expectCompletion();
+663        sub2.expectCompletion();
+664        sub3.expectCompletion();
+665
+666        assertEquals(received1, received2, String.format("Expected elements to be signaled in the same sequence to 1st and 2nd subscribers"));
+667        assertEquals(received2, received3, String.format("Expected elements to be signaled in the same sequence to 2nd and 3rd subscribers"));
+668      }
+669    });
+670  }
+671
+672  ///////////////////// SUBSCRIPTION TESTS //////////////////////////////////
+673
+674  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.2
+675  @Override @Test
+676  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+677    activePublisherTest(6, false, new PublisherTestRun<T>() {
+678      @Override
+679      public void run(Publisher<T> pub) throws Throwable {
+680        ManualSubscriber<T> sub = new ManualSubscriber<T>(env) {
+681          @Override
+682          public void onSubscribe(Subscription subs) {
+683            this.subscription.completeImmediatly(subs);
+684
+685            subs.request(1);
+686            subs.request(1);
+687            subs.request(1);
+688          }
+689
+690          @Override
+691          public void onNext(T element) {
+692            Subscription subs = this.subscription.value();
+693            subs.request(1);
+694          }
+695        };
+696
+697        env.subscribe(pub, sub);
+698
+699        long delay = env.defaultTimeoutMillis();
+700        env.verifyNoAsyncErrors(delay);
+701      }
+702    });
+703  }
+704
+705  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.3
+706  @Override @Test
+707  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+708    final long oneMoreThanBoundedLimit = boundedDepthOfOnNextAndRequestRecursion() + 1;
+709
+710    activePublisherTest(oneMoreThanBoundedLimit, false, new PublisherTestRun<T>() {
+711      @Override
+712      public void run(Publisher<T> pub) throws Throwable {
+713        final ThreadLocal<Long> stackDepthCounter = new ThreadLocal<Long>() {
+714          @Override
+715          protected Long initialValue() {
+716            return 0L;
+717          }
+718        };
+719
+720        final Latch runCompleted = new Latch(env);
+721
+722        final ManualSubscriber<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+723          // counts the number of signals received, used to break out from possibly infinite request/onNext loops
+724          long signalsReceived = 0L;
+725
+726          @Override
+727          public void onNext(T element) {
+728            // NOT calling super.onNext as this test only cares about stack depths, not the actual values of elements
+729            // which also simplifies this test as we do not have to drain the test buffer, which would otherwise be in danger of overflowing
+730
+731            signalsReceived += 1;
+732            stackDepthCounter.set(stackDepthCounter.get() + 1);
+733            env.debug(String.format("%s(recursion depth: %d)::onNext(%s)", this, stackDepthCounter.get(), element));
+734
+735            final long callsUntilNow = stackDepthCounter.get();
+736            if (callsUntilNow > boundedDepthOfOnNextAndRequestRecursion()) {
+737              env.flop(String.format("Got %d onNext calls within thread: %s, yet expected recursive bound was %d",
+738                                     callsUntilNow, Thread.currentThread(), boundedDepthOfOnNextAndRequestRecursion()));
+739
+740              // stop the recursive call chain
+741              runCompleted.close();
+742              return;
+743            } else if (signalsReceived >= oneMoreThanBoundedLimit) {
+744              // since max number of signals reached, and recursion depth not exceeded, we judge this as a success and
+745              // stop the recursive call chain
+746              runCompleted.close();
+747              return;
+748            }
+749
+750            // request more right away, the Publisher must break the recursion
+751            subscription.value().request(1);
+752
+753            stackDepthCounter.set(stackDepthCounter.get() - 1);
+754          }
+755
+756          @Override
+757          public void onComplete() {
+758            super.onComplete();
+759            runCompleted.close();
+760          }
+761
+762          @Override
+763          public void onError(Throwable cause) {
+764            super.onError(cause);
+765            runCompleted.close();
+766          }
+767        };
+768
+769        try {
+770          env.subscribe(pub, sub);
+771
+772          sub.request(1); // kick-off the `request -> onNext -> request -> onNext -> ...`
+773
+774          final String msg = String.format("Unable to validate call stack depth safety, " +
+775                                               "awaited at-most %s signals (`maxOnNextSignalsInRecursionTest()`) or completion",
+776                                           oneMoreThanBoundedLimit);
+777          runCompleted.expectClose(env.defaultTimeoutMillis(), msg);
+778          env.verifyNoAsyncErrorsNoDelay();
+779        } finally {
+780          // since the request/onNext recursive calls may keep the publisher running "forever",
+781          // we MUST cancel it manually before exiting this test case
+782          sub.cancel();
+783        }
+784      }
+785    });
+786  }
+787
+788  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.4
+789  @Override @Test
+790  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+791    notVerified(); // cannot be meaningfully tested, or can it?
+792  }
+793
+794  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.5
+795  @Override @Test
+796  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() throws Exception {
+797    notVerified(); // cannot be meaningfully tested, or can it?
+798  }
+799
+800  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.6
+801  @Override @Test
+802  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+803    activePublisherTest(3, false, new PublisherTestRun<T>() {
+804      @Override
+805      public void run(Publisher<T> pub) throws Throwable {
+806
+807        // override ManualSubscriberWithSubscriptionSupport#cancel because by default a ManualSubscriber will drop the
+808        // subscription once it's cancelled (as expected).
+809        // In this test however it must keep the cancelled Subscription and keep issuing `request(long)` to it.
+810        ManualSubscriber<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+811          @Override
+812          public void cancel() {
+813            if (subscription.isCompleted()) {
+814              subscription.value().cancel();
+815            } else {
+816              env.flop("Cannot cancel a subscription before having received it");
+817            }
+818          }
+819        };
+820
+821        env.subscribe(pub, sub);
+822
+823        sub.cancel();
+824        sub.request(1);
+825        sub.request(1);
+826        sub.request(1);
+827
+828        sub.expectNone();
+829        env.verifyNoAsyncErrorsNoDelay();
+830      }
+831    });
+832  }
+833
+834  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.7
+835  @Override @Test
+836  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+837    activePublisherTest(1, false, new PublisherTestRun<T>() {
+838      @Override
+839      public void run(Publisher<T> pub) throws Throwable {
+840        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+841
+842        // leak the Subscription
+843        final Subscription subs = sub.subscription.value();
+844
+845        subs.cancel();
+846        subs.cancel();
+847        subs.cancel();
+848
+849        sub.expectNone();
+850        env.verifyNoAsyncErrorsNoDelay();
+851      }
+852    });
+853  }
+854
+855  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.9
+856  @Override @Test
+857  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+858    activePublisherTest(10, false, new PublisherTestRun<T>() {
+859      @Override public void run(Publisher<T> pub) throws Throwable {
+860        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+861        sub.request(0);
+862        sub.expectErrorWithMessage(IllegalArgumentException.class, "3.9"); // we do require implementations to mention the rule number at the very least
+863      }
+864    });
+865  }
+866
+867  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.9
+868  @Override @Test
+869  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+870    activePublisherTest(10, false, new PublisherTestRun<T>() {
+871      @Override
+872      public void run(Publisher<T> pub) throws Throwable {
+873        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+874        final Random r = new Random();
+875        sub.request(-r.nextInt(Integer.MAX_VALUE));
+876        sub.expectErrorWithMessage(IllegalArgumentException.class, "3.9"); // we do require implementations to mention the rule number at the very least
+877      }
+878    });
+879  }
+880
+881  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.12
+882  @Override @Test
+883  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+884    // the publisher is able to signal more elements than the subscriber will be requesting in total
+885    final int publisherElements = 20;
+886
+887    final int demand1 = 10;
+888    final int demand2 = 5;
+889    final int totalDemand = demand1 + demand2;
+890
+891    activePublisherTest(publisherElements, false, new PublisherTestRun<T>() {
+892      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+893      public void run(Publisher<T> pub) throws Throwable {
+894        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+895
+896        sub.request(demand1);
+897        sub.request(demand2);
+898
+899        /*
+900          NOTE: The order of the nextElement/cancel calls below is very important (!)
+901
+902          If this ordering was reversed, given an asynchronous publisher,
+903          the following scenario would be *legal* and would break this test:
+904
+905          > AsyncPublisher receives request(10) - it does not emit data right away, it's asynchronous
+906          > AsyncPublisher receives request(5) - demand is now 15
+907          ! AsyncPublisher didn't emit any onNext yet (!)
+908          > AsyncPublisher receives cancel() - handles it right away, by "stopping itself" for example
+909          ! cancel was handled hefore the AsyncPublisher ever got the chance to emit data
+910          ! the subscriber ends up never receiving even one element - the test is stuck (and fails, even on valid Publisher)
+911
+912          Which is why we must first expect an element, and then cancel, once the producing is "running".
+913         */
+914        sub.nextElement();
+915        sub.cancel();
+916
+917        int onNextsSignalled = 1;
+918
+919        boolean stillBeingSignalled;
+920        do {
+921          // put asyncError if onNext signal received
+922          sub.expectNone();
+923          Throwable error = env.dropAsyncError();
+924
+925          if (error == null) {
+926            stillBeingSignalled = false;
+927          } else {
+928            onNextsSignalled += 1;
+929            stillBeingSignalled = true;
+930          }
+931
+932          // if the Publisher tries to emit more elements than was requested (and/or ignores cancellation) this will throw
+933          assertTrue(onNextsSignalled <= totalDemand,
+934                     String.format("Publisher signalled [%d] elements, which is more than the signalled demand: %d",
+935                                   onNextsSignalled, totalDemand));
+936
+937        } while (stillBeingSignalled);
+938      }
+939    });
+940
+941    env.verifyNoAsyncErrorsNoDelay();
+942  }
+943
+944  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.13
+945  @Override @Test
+946  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+947    final ReferenceQueue<ManualSubscriber<T>> queue = new ReferenceQueue<ManualSubscriber<T>>();
+948
+949    final Function<Publisher<T>, WeakReference<ManualSubscriber<T>>> run = new Function<Publisher<T>, WeakReference<ManualSubscriber<T>>>() {
+950      @Override
+951      public WeakReference<ManualSubscriber<T>> apply(Publisher<T> pub) throws Exception {
+952        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+953        final WeakReference<ManualSubscriber<T>> ref = new WeakReference<ManualSubscriber<T>>(sub, queue);
+954
+955        sub.request(1);
+956        sub.nextElement();
+957        sub.cancel();
+958
+959        return ref;
+960      }
+961    };
+962
+963    activePublisherTest(3, false, new PublisherTestRun<T>() {
+964      @Override
+965      public void run(Publisher<T> pub) throws Throwable {
+966        final WeakReference<ManualSubscriber<T>> ref = run.apply(pub);
+967
+968        // cancel may be run asynchronously so we add a sleep before running the GC
+969        // to "resolve" the race
+970        Thread.sleep(publisherReferenceGCTimeoutMillis);
+971        System.gc();
+972
+973        if (!ref.equals(queue.remove(100))) {
+974          env.flop(String.format("Publisher %s did not drop reference to test subscriber after subscription cancellation", pub));
+975        }
+976
+977        env.verifyNoAsyncErrorsNoDelay();
+978      }
+979    });
+980  }
+981
+982  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.17
+983  @Override @Test
+984  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+985    final int totalElements = 3;
+986
+987    activePublisherTest(totalElements, true, new PublisherTestRun<T>() {
+988      @Override
+989      public void run(Publisher<T> pub) throws Throwable {
+990        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+991        sub.request(Long.MAX_VALUE);
+992
+993        sub.nextElements(totalElements);
+994        sub.expectCompletion();
+995
+996        env.verifyNoAsyncErrorsNoDelay();
+997      }
+998    });
+999  }
+1000
+1001  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.17
+1002  @Override @Test
+1003  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+1004    final int totalElements = 3;
+1005
+1006    activePublisherTest(totalElements, true, new PublisherTestRun<T>() {
+1007      @Override
+1008      public void run(Publisher<T> pub) throws Throwable {
+1009        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+1010        sub.request(Long.MAX_VALUE / 2); // pending = Long.MAX_VALUE / 2
+1011        sub.request(Long.MAX_VALUE / 2); // pending = Long.MAX_VALUE - 1
+1012        sub.request(1); // pending = Long.MAX_VALUE
+1013
+1014        sub.nextElements(totalElements);
+1015        sub.expectCompletion();
+1016
+1017        try {
+1018          env.verifyNoAsyncErrorsNoDelay();
+1019        } finally {
+1020          sub.cancel();
+1021        }
+1022        
+1023      }
+1024    });
+1025  }
+1026
+1027  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.17
+1028  @Override @Test
+1029  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+1030    activePublisherTest(Integer.MAX_VALUE, false, new PublisherTestRun<T>() {
+1031      @Override public void run(Publisher<T> pub) throws Throwable {
+1032        final ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(env) {
+1033           // arbitrarily set limit on nuber of request calls signalled, we expect overflow after already 2 calls,
+1034           // so 10 is relatively high and safe even if arbitrarily chosen
+1035          int callsCounter = 10;
+1036
+1037          @Override
+1038          public void onNext(T element) {
+1039            env.debug(String.format("%s::onNext(%s)", this, element));
+1040            if (subscription.isCompleted()) {
+1041              if (callsCounter > 0) {
+1042                subscription.value().request(Long.MAX_VALUE - 1);
+1043                callsCounter--;
+1044              } else {
+1045                  subscription.value().cancel();
+1046              }
+1047            } else {
+1048              env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+1049            }
+1050          }
+1051        };
+1052        env.subscribe(pub, sub, env.defaultTimeoutMillis());
+1053
+1054        // eventually triggers `onNext`, which will then trigger up to `callsCounter` times `request(Long.MAX_VALUE - 1)`
+1055        // we're pretty sure to overflow from those
+1056        sub.request(1);
+1057
+1058        // no onError should be signalled
+1059        try {
+1060          env.verifyNoAsyncErrors(env.defaultTimeoutMillis());
+1061        } finally {
+1062          sub.cancel();
+1063        }
+1064      }
+1065    });
+1066  }
+1067
+1068  ///////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+1069
+1070  ///////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+1071
+1072  public interface PublisherTestRun<T> {
+1073    public void run(Publisher<T> pub) throws Throwable;
+1074  }
+1075
+1076  /**
+1077   * Test for feature that SHOULD/MUST be implemented, using a live publisher.
+1078   *
+1079   * @param elements the number of elements the Publisher under test  must be able to emit to run this test
+1080   * @param completionSignalRequired true if an {@code onComplete} signal is required by this test to run.
+1081   *                                 If the tested Publisher is unable to signal completion, tests requireing onComplete signals will be skipped.
+1082   *                                 To signal if your Publisher is able to signal completion see {@link PublisherVerification#maxElementsFromPublisher()}.
+1083   */
+1084  public void activePublisherTest(long elements, boolean completionSignalRequired, PublisherTestRun<T> body) throws Throwable {
+1085    if (elements > maxElementsFromPublisher()) {
+1086      throw new SkipException(String.format("Unable to run this test, as required elements nr: %d is higher than supported by given producer: %d", elements, maxElementsFromPublisher()));
+1087    } else if (completionSignalRequired && maxElementsFromPublisher() == Long.MAX_VALUE) {
+1088      throw new SkipException("Unable to run this test, as it requires an onComplete signal, " +
+1089                                "which this Publisher is unable to provide (as signalled by returning Long.MAX_VALUE from `maxElementsFromPublisher()`)");
+1090    } else {
+1091      Publisher<T> pub = createPublisher(elements);
+1092      body.run(pub);
+1093      env.verifyNoAsyncErrorsNoDelay();
+1094    }
+1095  }
+1096
+1097  /**
+1098   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+1099   *
+1100   * @param elements the number of elements the Publisher under test  must be able to emit to run this test
+1101   * @param completionSignalRequired true if an {@code onComplete} signal is required by this test to run.
+1102   *                                 If the tested Publisher is unable to signal completion, tests requireing onComplete signals will be skipped.
+1103   *                                 To signal if your Publisher is able to signal completion see {@link PublisherVerification#maxElementsFromPublisher()}.
+1104   */
+1105  public void optionalActivePublisherTest(long elements, boolean completionSignalRequired, PublisherTestRun<T> body) throws Throwable {
+1106    if (elements > maxElementsFromPublisher()) {
+1107      throw new SkipException(String.format("Unable to run this test, as required elements nr: %d is higher than supported by given producer: %d", elements, maxElementsFromPublisher()));
+1108    } else if (completionSignalRequired && maxElementsFromPublisher() == Long.MAX_VALUE) {
+1109      throw new SkipException("Unable to run this test, as it requires an onComplete signal, " +
+1110                                "which this Publisher is unable to provide (as signalled by returning Long.MAX_VALUE from `maxElementsFromPublisher()`)");
+1111    } else {
+1112
+1113      final Publisher<T> pub = createPublisher(elements);
+1114      final String skipMessage = "Skipped because tested publisher does NOT implement this OPTIONAL requirement.";
+1115
+1116      try {
+1117        potentiallyPendingTest(pub, body);
+1118      } catch (Exception ex) {
+1119        notVerified(skipMessage);
+1120      } catch (AssertionError ex) {
+1121        notVerified(skipMessage + " Reason for skipping was: " + ex.getMessage());
+1122      }
+1123    }
+1124  }
+1125
+1126  public static final String SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE =
+1127    "Skipping because no error state Publisher provided, and the test requires it. " +
+1128          "Please implement PublisherVerification#createFailedPublisher to run this test.";
+1129
+1130  public static final String SKIPPING_OPTIONAL_TEST_FAILED =
+1131    "Skipping, because provided Publisher does not pass this *additional* verification.";
+1132  /**
+1133   * Additional test for Publisher in error state
+1134   */
+1135  public void whenHasErrorPublisherTest(PublisherTestRun<T> body) throws Throwable {
+1136    potentiallyPendingTest(createFailedPublisher(), body, SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE);
+1137  }
+1138
+1139  public void potentiallyPendingTest(Publisher<T> pub, PublisherTestRun<T> body) throws Throwable {
+1140    potentiallyPendingTest(pub, body, SKIPPING_OPTIONAL_TEST_FAILED);
+1141  }
+1142
+1143  public void potentiallyPendingTest(Publisher<T> pub, PublisherTestRun<T> body, String message) throws Throwable {
+1144    if (pub != null) {
+1145      body.run(pub);
+1146    } else {
+1147      throw new SkipException(message);
+1148    }
+1149  }
+1150
+1151  /**
+1152   * Executes a given test body {@code n} times.
+1153   * All the test runs must pass in order for the stochastic test to pass.
+1154   */
+1155  public void stochasticTest(int n, Function<Integer, Void> body) throws Throwable {
+1156    if (skipStochasticTests()) {
+1157      notVerified("Skipping @Stochastic test because `skipStochasticTests()` returned `true`!");
+1158    }
+1159
+1160    for (int i = 0; i < n; i++) {
+1161      body.apply(i);
+1162    }
+1163  }
+1164
+1165  public void notVerified() {
+1166    throw new SkipException("Not verified by this TCK.");
+1167  }
+1168
+1169  /**
+1170   * Return this value from {@link PublisherVerification#maxElementsFromPublisher()} to mark that the given {@link org.reactivestreams.Publisher},
+1171   * is not able to signal completion. For example it is strictly a time-bound or unbounded source of data.
+1172   *
+1173   * <b>Returning this value from {@link PublisherVerification#maxElementsFromPublisher()} will result in skipping all TCK tests which require onComplete signals!</b>
+1174   */
+1175  public long publisherUnableToSignalOnComplete() {
+1176    return Long.MAX_VALUE;
+1177  }
+1178
+1179  public void notVerified(String message) {
+1180    throw new SkipException(message);
+1181  }
+1182
+1183}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.html new file mode 100644 index 0000000..62bc3dc --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/PublisherVerification.html @@ -0,0 +1,1255 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport;
+007import org.reactivestreams.tck.TestEnvironment.Latch;
+008import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+009import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+010import org.reactivestreams.tck.support.Function;
+011import org.reactivestreams.tck.support.Optional;
+012import org.reactivestreams.tck.support.PublisherVerificationRules;
+013import org.testng.SkipException;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.lang.Override;
+018import java.lang.ref.ReferenceQueue;
+019import java.lang.ref.WeakReference;
+020import java.util.ArrayList;
+021import java.util.Arrays;
+022import java.util.Collections;
+023import java.util.List;
+024import java.util.Random;
+025import java.util.concurrent.atomic.AtomicReference;
+026
+027import static org.testng.Assert.assertEquals;
+028import static org.testng.Assert.assertTrue;
+029
+030/**
+031 * Provides tests for verifying {@code Publisher} specification rules.
+032 *
+033 * @see org.reactivestreams.Publisher
+034 */
+035public abstract class PublisherVerification<T> implements PublisherVerificationRules {
+036
+037  private static final String PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV = "PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS";
+038  private static final long DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS = 300L;
+039
+040  private final TestEnvironment env;
+041
+042  /**
+043   * The amount of time after which a cancelled Subscriber reference should be dropped.
+044   * See Rule 3.13 for details.
+045   */
+046  private final long publisherReferenceGCTimeoutMillis;
+047
+048  /**
+049   * Constructs a new verification class using the given env and configuration.
+050   *
+051   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+052   */
+053  public PublisherVerification(TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+054    this.env = env;
+055    this.publisherReferenceGCTimeoutMillis = publisherReferenceGCTimeoutMillis;
+056  }
+057
+058  /**
+059   * Constructs a new verification class using the given env and configuration.
+060   *
+061   * The value for {@code publisherReferenceGCTimeoutMillis} will be obtained by using {@link PublisherVerification#envPublisherReferenceGCTimeoutMillis()}.
+062   */
+063  public PublisherVerification(TestEnvironment env) {
+064    this.env = env;
+065    this.publisherReferenceGCTimeoutMillis = envPublisherReferenceGCTimeoutMillis();
+066  }
+067
+068  /**
+069   * Tries to parse the env variable {@code PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS} as long and returns the value if present,
+070   * OR its default value ({@link PublisherVerification#DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS}).
+071   *
+072   * This value is used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+073   *
+074   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+075   */
+076  public static long envPublisherReferenceGCTimeoutMillis() {
+077    final String envMillis = System.getenv(PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV);
+078    if (envMillis == null) return DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS;
+079    else try {
+080      return Long.parseLong(envMillis);
+081    } catch(NumberFormatException ex) {
+082      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV, envMillis), ex);
+083    }
+084  }
+085
+086  /**
+087   * This is the main method you must implement in your test incarnation.
+088   * It must create a Publisher for a stream with exactly the given number of elements.
+089   * If `elements` is `Long.MAX_VALUE` the produced stream must be infinite.
+090   */
+091  public abstract Publisher<T> createPublisher(long elements);
+092
+093  /**
+094   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+095   *
+096   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+097   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+098   *
+099   * If you ignore these additional tests, return {@code null} from this method.
+100   */
+101  public abstract Publisher<T> createFailedPublisher();
+102
+103
+104  /**
+105   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+106   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+107   *
+108   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+109   *
+110   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+111   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+112   */
+113  public long maxElementsFromPublisher() {
+114    return Long.MAX_VALUE - 1;
+115  }
+116
+117  /**
+118   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+119   * Such tests MAY sometimes fail even though the impl
+120   */
+121  public boolean skipStochasticTests() {
+122    return false;
+123  }
+124
+125  /**
+126   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+127   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+128   * recursive calls to exceed the number returned by this method.
+129   *
+130   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+131   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+132   */
+133  public long boundedDepthOfOnNextAndRequestRecursion() {
+134    return 1;
+135  }
+136
+137  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+138
+139  @BeforeMethod
+140  public void setUp() throws Exception {
+141    env.clearAsyncErrors();
+142  }
+143
+144  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+145
+146  @Override @Test
+147  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+148    activePublisherTest(1, true, new PublisherTestRun<T>() {
+149      @Override
+150      public void run(Publisher<T> pub) throws InterruptedException {
+151        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+152        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced no elements", pub));
+153        sub.requestEndOfStream();
+154      }
+155
+156      Optional<T> requestNextElementOrEndOfStream(Publisher<T> pub, ManualSubscriber<T> sub) throws InterruptedException {
+157        return sub.requestNextElementOrEndOfStream(String.format("Timeout while waiting for next element from Publisher %s", pub));
+158      }
+159
+160    });
+161  }
+162
+163  @Override @Test
+164  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+165    activePublisherTest(3, true, new PublisherTestRun<T>() {
+166      @Override
+167      public void run(Publisher<T> pub) throws InterruptedException {
+168        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+169        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced no elements", pub));
+170        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced only 1 element", pub));
+171        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced only 2 elements", pub));
+172        sub.requestEndOfStream();
+173      }
+174
+175      Optional<T> requestNextElementOrEndOfStream(Publisher<T> pub, ManualSubscriber<T> sub) throws InterruptedException {
+176        return sub.requestNextElementOrEndOfStream(String.format("Timeout while waiting for next element from Publisher %s", pub));
+177      }
+178
+179    });
+180  }
+181
+182  @Override @Test
+183  public void required_validate_maxElementsFromPublisher() throws Exception {
+184    assertTrue(maxElementsFromPublisher() >= 0, "maxElementsFromPublisher MUST return a number >= 0");
+185  }
+186
+187  @Override @Test
+188  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+189    assertTrue(boundedDepthOfOnNextAndRequestRecursion() >= 1, "boundedDepthOfOnNextAndRequestRecursion must return a number >= 1");
+190  }
+191
+192
+193  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+194
+195  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.1
+196  @Override @Test
+197  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+198    activePublisherTest(5, false, new PublisherTestRun<T>() {
+199      @Override
+200      public void run(Publisher<T> pub) throws InterruptedException {
+201
+202        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+203
+204        sub.expectNone(String.format("Publisher %s produced value before the first `request`: ", pub));
+205        sub.request(1);
+206        sub.nextElement(String.format("Publisher %s produced no element after first `request`", pub));
+207        sub.expectNone(String.format("Publisher %s produced unrequested: ", pub));
+208
+209        sub.request(1);
+210        sub.request(2);
+211        sub.nextElements(3, env.defaultTimeoutMillis(), String.format("Publisher %s produced less than 3 elements after two respective `request` calls", pub));
+212
+213        sub.expectNone(String.format("Publisher %sproduced unrequested ", pub));
+214      }
+215    });
+216  }
+217
+218  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.2
+219  @Override @Test
+220  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+221    final int elements = 3;
+222    final int requested = 10;
+223
+224    activePublisherTest(elements, true, new PublisherTestRun<T>() {
+225      @Override
+226      public void run(Publisher<T> pub) throws Throwable {
+227        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+228        sub.request(requested);
+229        sub.nextElements(elements);
+230        sub.expectCompletion();
+231      }
+232    });
+233  }
+234
+235  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.3
+236  @Override @Test
+237  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+238    final int iterations = 100;
+239    final int elements = 10;
+240
+241    stochasticTest(iterations, new Function<Integer, Void>() {
+242      @Override
+243      public Void apply(final Integer runNumber) throws Throwable {
+244        activePublisherTest(elements, true, new PublisherTestRun<T>() {
+245          @Override
+246          public void run(Publisher<T> pub) throws Throwable {
+247            final Latch completionLatch = new Latch(env);
+248
+249            pub.subscribe(new Subscriber<T>() {
+250              private Subscription subs;
+251              private long gotElements = 0;
+252
+253              private ConcurrentAccessBarrier concurrentAccessBarrier = new ConcurrentAccessBarrier();
+254
+255              /**
+256               * Concept wise very similar to a {@link org.reactivestreams.tck.TestEnvironment.Latch}, serves to protect
+257               * a critical section from concurrent access, with the added benefit of Thread tracking and same-thread-access awareness.
+258               *
+259               * Since a <i>Synchronous</i> Publisher may choose to synchronously (using the same {@link Thread}) call
+260               * {@code onNext} directly from either {@code subscribe} or {@code request} a plain Latch is not enough
+261               * to verify concurrent access safety - one needs to track if the caller is not still using the calling thread
+262               * to enter subsequent critical sections ("nesting" them effectively).
+263               */
+264              final class ConcurrentAccessBarrier {
+265                private AtomicReference<Thread> currentlySignallingThread = new AtomicReference<Thread>(null);
+266                private volatile String previousSignal = null;
+267
+268                public void enterSignal(String signalName) {
+269                  if((!currentlySignallingThread.compareAndSet(null, Thread.currentThread())) && !isSynchronousSignal()) {
+270                    env.flop(String.format(
+271                      "Illegal concurrent access detected (entering critical section)! " +
+272                        "%s emited %s signal, before %s finished its %s signal.",
+273                        Thread.currentThread(), signalName, currentlySignallingThread.get(), previousSignal));
+274                  }
+275                  this.previousSignal = signalName;
+276                }
+277
+278                public void leaveSignal(String signalName) {
+279                  currentlySignallingThread.set(null);
+280                  this.previousSignal = signalName;
+281                }
+282
+283                private boolean isSynchronousSignal() {
+284                  return (previousSignal != null) && Thread.currentThread().equals(currentlySignallingThread.get());
+285                }
+286
+287              }
+288
+289              @Override
+290              public void onSubscribe(Subscription s) {
+291                final String signal = "onSubscribe()";
+292                concurrentAccessBarrier.enterSignal(signal);
+293
+294                subs = s;
+295                subs.request(1);
+296
+297                concurrentAccessBarrier.leaveSignal(signal);
+298              }
+299
+300              @Override
+301              public void onNext(T ignore) {
+302                final String signal = String.format("onNext(%s)", ignore);
+303                concurrentAccessBarrier.enterSignal(signal);
+304
+305                gotElements += 1;
+306                if (gotElements <= elements) // requesting one more than we know are in the stream (some Publishers need this)
+307                  subs.request(1);
+308
+309                concurrentAccessBarrier.leaveSignal(signal);
+310              }
+311
+312              @Override
+313              public void onError(Throwable t) {
+314                final String signal = String.format("onError(%s)", t.getMessage());
+315                concurrentAccessBarrier.enterSignal(signal);
+316
+317                // ignore value
+318
+319                concurrentAccessBarrier.leaveSignal(signal);
+320              }
+321
+322              @Override
+323              public void onComplete() {
+324                final String signal = "onComplete()";
+325                concurrentAccessBarrier.enterSignal(signal);
+326
+327                // entering for completeness
+328
+329                concurrentAccessBarrier.leaveSignal(signal);
+330                completionLatch.close();
+331              }
+332            });
+333
+334            completionLatch.expectClose(elements * env.defaultTimeoutMillis(), "Expected 10 elements to be drained");
+335          }
+336        });
+337        return null;
+338      }
+339    });
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.4
+343  @Override @Test
+344  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+345    try {
+346      whenHasErrorPublisherTest(new PublisherTestRun<T>() {
+347        @Override
+348        public void run(final Publisher<T> pub) throws InterruptedException {
+349          final Latch onErrorlatch = new Latch(env);
+350          final Latch onSubscribeLatch = new Latch(env);
+351          pub.subscribe(new TestEnvironment.TestSubscriber<T>(env) {
+352            @Override
+353            public void onSubscribe(Subscription subs) {
+354              onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+355              onSubscribeLatch.close();
+356            }
+357            @Override
+358            public void onError(Throwable cause) {
+359              onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+360              onErrorlatch.assertOpen(String.format("Error-state Publisher %s called `onError` twice on new Subscriber", pub));
+361              onErrorlatch.close();
+362            }
+363          });
+364
+365          onSubscribeLatch.expectClose("Should have received onSubscribe");
+366          onErrorlatch.expectClose(String.format("Error-state Publisher %s did not call `onError` on new Subscriber", pub));
+367
+368          env.verifyNoAsyncErrors(env.defaultTimeoutMillis());
+369          }
+370      });
+371    } catch (SkipException se) {
+372      throw se;
+373    } catch (Throwable ex) {
+374      // we also want to catch AssertionErrors and anything the publisher may have thrown inside subscribe
+375      // which was wrong of him - he should have signalled on error using onError
+376      throw new RuntimeException(String.format("Publisher threw exception (%s) instead of signalling error via onError!", ex.getMessage()), ex);
+377    }
+378  }
+379
+380  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.5
+381  @Override @Test
+382  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+383    activePublisherTest(3, true, new PublisherTestRun<T>() {
+384      @Override
+385      public void run(Publisher<T> pub) throws Throwable {
+386        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+387        sub.requestNextElement();
+388        sub.requestNextElement();
+389        sub.requestNextElement();
+390        sub.requestEndOfStream();
+391        sub.expectNone();
+392      }
+393    });
+394  }
+395
+396  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.5
+397  @Override @Test
+398  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+399    optionalActivePublisherTest(0, true, new PublisherTestRun<T>() {
+400      @Override
+401      public void run(Publisher<T> pub) throws Throwable {
+402        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+403        sub.request(1);
+404        sub.expectCompletion();
+405        sub.expectNone();
+406      }
+407    });
+408  }
+409
+410  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.6
+411  @Override @Test
+412  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+413    notVerified(); // not really testable without more control over the Publisher
+414  }
+415
+416  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.7
+417  @Override @Test
+418  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+419    activePublisherTest(1, true, new PublisherTestRun<T>() {
+420      @Override
+421      public void run(Publisher<T> pub) throws Throwable {
+422        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+423        sub.request(10);
+424        sub.nextElement();
+425        sub.expectCompletion();
+426
+427        sub.request(10);
+428        sub.expectNone();
+429      }
+430    });
+431  }
+432
+433  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.7
+434  @Override @Test
+435  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+436    notVerified(); // can we meaningfully test this, without more control over the publisher?
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.8
+440  @Override @Test
+441  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+442    notVerified(); // can we meaningfully test this?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+446  @Override @Test
+447  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+448    notVerified(); // can we meaningfully test this?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+452  @Override @Test
+453  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+454    activePublisherTest(0, false, new PublisherTestRun<T>() {
+455      @Override
+456      public void run(Publisher<T> pub) throws Throwable {
+457        try {
+458            pub.subscribe(null);
+459            env.flop("Publisher did not throw a NullPointerException when given a null Subscribe in subscribe");
+460        } catch (NullPointerException ignored) {
+461          // valid behaviour
+462        }
+463        env.verifyNoAsyncErrorsNoDelay();
+464      }
+465    });
+466  }
+467
+468  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+469  @Override @Test
+470  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+471    activePublisherTest(0, false, new PublisherTestRun<T>() {
+472      @Override
+473      public void run(Publisher<T> pub) throws Throwable {
+474        final Latch onSubscribeLatch = new Latch(env);
+475        pub.subscribe(new Subscriber<T>() {
+476          @Override
+477          public void onError(Throwable cause) {
+478            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+479          }
+480
+481          @Override
+482          public void onSubscribe(Subscription subs) {
+483            onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+484            onSubscribeLatch.close();
+485          }
+486
+487          @Override
+488          public void onNext(T elem) {
+489            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onNext always");
+490          }
+491
+492          @Override
+493          public void onComplete() {
+494            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onComplete always");
+495          }
+496        });
+497        onSubscribeLatch.expectClose("Should have received onSubscribe");
+498        env.verifyNoAsyncErrorsNoDelay();
+499      }
+500    });
+501  }
+502
+503  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.9
+504  @Override @Test
+505  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+506    whenHasErrorPublisherTest(new PublisherTestRun<T>() {
+507      @Override
+508      public void run(Publisher<T> pub) throws Throwable {
+509        final Latch onErrorLatch = new Latch(env);
+510        final Latch onSubscribeLatch = new Latch(env);
+511        ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+512          @Override
+513          public void onError(Throwable cause) {
+514            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+515            onErrorLatch.assertOpen("Only one onError call expected");
+516            onErrorLatch.close();
+517          }
+518
+519          @Override
+520          public void onSubscribe(Subscription subs) {
+521            onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+522            onSubscribeLatch.close();
+523          }
+524        };
+525        pub.subscribe(sub);
+526        onSubscribeLatch.expectClose("Should have received onSubscribe");
+527        onErrorLatch.expectClose("Should have received onError");
+528
+529        env.verifyNoAsyncErrorsNoDelay();
+530      }
+531    });
+532  }
+533
+534    // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.10
+535  @Override @Test
+536  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+537    notVerified(); // can we meaningfully test this?
+538  }
+539
+540  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+541  @Override @Test
+542  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+543    optionalActivePublisherTest(1, false, new PublisherTestRun<T>() {
+544      @Override
+545      public void run(Publisher<T> pub) throws Throwable {
+546        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+547        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+548
+549        env.verifyNoAsyncErrors();
+550      }
+551    });
+552  }
+553
+554  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+555  @Override @Test
+556  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+557    optionalActivePublisherTest(5, true, new PublisherTestRun<T>() { // This test is skipped if the publisher is unbounded (never sends onComplete)
+558      @Override
+559      public void run(Publisher<T> pub) throws InterruptedException {
+560        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+561        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+562        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+563
+564        sub1.request(1);
+565        T x1 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+566        sub2.request(2);
+567        List<T> y1 = sub2.nextElements(2, String.format("Publisher %s did not produce the requested 2 elements on 2nd subscriber", pub));
+568        sub1.request(1);
+569        T x2 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+570        sub3.request(3);
+571        List<T> z1 = sub3.nextElements(3, String.format("Publisher %s did not produce the requested 3 elements on 3rd subscriber", pub));
+572        sub3.request(1);
+573        T z2 = sub3.nextElement(String.format("Publisher %s did not produce the requested 1 element on 3rd subscriber", pub));
+574        sub3.request(1);
+575        T z3 = sub3.nextElement(String.format("Publisher %s did not produce the requested 1 element on 3rd subscriber", pub));
+576        sub3.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 3rd subscriber", pub));
+577        sub2.request(3);
+578        List<T> y2 = sub2.nextElements(3, String.format("Publisher %s did not produce the requested 3 elements on 2nd subscriber", pub));
+579        sub2.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 2nd subscriber", pub));
+580        sub1.request(2);
+581        List<T> x3 = sub1.nextElements(2, String.format("Publisher %s did not produce the requested 2 elements on 1st subscriber", pub));
+582        sub1.request(1);
+583        T x4 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+584        sub1.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 1st subscriber", pub));
+585
+586        @SuppressWarnings("unchecked")
+587        List<T> r = new ArrayList<T>(Arrays.asList(x1, x2));
+588        r.addAll(x3);
+589        r.addAll(Collections.singleton(x4));
+590
+591        List<T> check1 = new ArrayList<T>(y1);
+592        check1.addAll(y2);
+593
+594        //noinspection unchecked
+595        List<T> check2 = new ArrayList<T>(z1);
+596        check2.add(z2);
+597        check2.add(z3);
+598
+599        assertEquals(r, check1, String.format("Publisher %s did not produce the same element sequence for subscribers 1 and 2", pub));
+600        assertEquals(r, check2, String.format("Publisher %s did not produce the same element sequence for subscribers 1 and 3", pub));
+601      }
+602    });
+603  }
+604
+605  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+606  @Override @Test
+607  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+608    optionalActivePublisherTest(3, false, new PublisherTestRun<T>() { // This test is skipped if the publisher cannot produce enough elements
+609      @Override
+610      public void run(Publisher<T> pub) throws Throwable {
+611        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+612        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+613        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+614
+615        List<T> received1 = new ArrayList<T>();
+616        List<T> received2 = new ArrayList<T>();
+617        List<T> received3 = new ArrayList<T>();
+618
+619        // if the publisher must touch it's source to notice it's been drained, the OnComplete won't come until we ask for more than it actually contains...
+620        // edgy edge case?
+621        sub1.request(4);
+622        sub2.request(4);
+623        sub3.request(4);
+624
+625        received1.addAll(sub1.nextElements(3));
+626        received2.addAll(sub2.nextElements(3));
+627        received3.addAll(sub3.nextElements(3));
+628
+629        // NOTE: can't check completion, the Publisher may not be able to signal it
+630        //       a similar test *with* completion checking is implemented
+631
+632        assertEquals(received1, received2, String.format("Expected elements to be signaled in the same sequence to 1st and 2nd subscribers"));
+633        assertEquals(received2, received3, String.format("Expected elements to be signaled in the same sequence to 2nd and 3rd subscribers"));
+634      }
+635    });
+636  }
+637
+638  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+639  @Override @Test
+640  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+641    optionalActivePublisherTest(3, true, new PublisherTestRun<T>() { // This test is skipped if the publisher is unbounded (never sends onComplete)
+642      @Override
+643      public void run(Publisher<T> pub) throws Throwable {
+644        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+645        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+646        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+647
+648        List<T> received1 = new ArrayList<T>();
+649        List<T> received2 = new ArrayList<T>();
+650        List<T> received3 = new ArrayList<T>();
+651
+652        // if the publisher must touch it's source to notice it's been drained, the OnComplete won't come until we ask for more than it actually contains...
+653        // edgy edge case?
+654        sub1.request(4);
+655        sub2.request(4);
+656        sub3.request(4);
+657
+658        received1.addAll(sub1.nextElements(3));
+659        received2.addAll(sub2.nextElements(3));
+660        received3.addAll(sub3.nextElements(3));
+661
+662        sub1.expectCompletion();
+663        sub2.expectCompletion();
+664        sub3.expectCompletion();
+665
+666        assertEquals(received1, received2, String.format("Expected elements to be signaled in the same sequence to 1st and 2nd subscribers"));
+667        assertEquals(received2, received3, String.format("Expected elements to be signaled in the same sequence to 2nd and 3rd subscribers"));
+668      }
+669    });
+670  }
+671
+672  ///////////////////// SUBSCRIPTION TESTS //////////////////////////////////
+673
+674  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.2
+675  @Override @Test
+676  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+677    activePublisherTest(6, false, new PublisherTestRun<T>() {
+678      @Override
+679      public void run(Publisher<T> pub) throws Throwable {
+680        ManualSubscriber<T> sub = new ManualSubscriber<T>(env) {
+681          @Override
+682          public void onSubscribe(Subscription subs) {
+683            this.subscription.completeImmediatly(subs);
+684
+685            subs.request(1);
+686            subs.request(1);
+687            subs.request(1);
+688          }
+689
+690          @Override
+691          public void onNext(T element) {
+692            Subscription subs = this.subscription.value();
+693            subs.request(1);
+694          }
+695        };
+696
+697        env.subscribe(pub, sub);
+698
+699        long delay = env.defaultTimeoutMillis();
+700        env.verifyNoAsyncErrors(delay);
+701      }
+702    });
+703  }
+704
+705  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.3
+706  @Override @Test
+707  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+708    final long oneMoreThanBoundedLimit = boundedDepthOfOnNextAndRequestRecursion() + 1;
+709
+710    activePublisherTest(oneMoreThanBoundedLimit, false, new PublisherTestRun<T>() {
+711      @Override
+712      public void run(Publisher<T> pub) throws Throwable {
+713        final ThreadLocal<Long> stackDepthCounter = new ThreadLocal<Long>() {
+714          @Override
+715          protected Long initialValue() {
+716            return 0L;
+717          }
+718        };
+719
+720        final Latch runCompleted = new Latch(env);
+721
+722        final ManualSubscriber<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+723          // counts the number of signals received, used to break out from possibly infinite request/onNext loops
+724          long signalsReceived = 0L;
+725
+726          @Override
+727          public void onNext(T element) {
+728            // NOT calling super.onNext as this test only cares about stack depths, not the actual values of elements
+729            // which also simplifies this test as we do not have to drain the test buffer, which would otherwise be in danger of overflowing
+730
+731            signalsReceived += 1;
+732            stackDepthCounter.set(stackDepthCounter.get() + 1);
+733            env.debug(String.format("%s(recursion depth: %d)::onNext(%s)", this, stackDepthCounter.get(), element));
+734
+735            final long callsUntilNow = stackDepthCounter.get();
+736            if (callsUntilNow > boundedDepthOfOnNextAndRequestRecursion()) {
+737              env.flop(String.format("Got %d onNext calls within thread: %s, yet expected recursive bound was %d",
+738                                     callsUntilNow, Thread.currentThread(), boundedDepthOfOnNextAndRequestRecursion()));
+739
+740              // stop the recursive call chain
+741              runCompleted.close();
+742              return;
+743            } else if (signalsReceived >= oneMoreThanBoundedLimit) {
+744              // since max number of signals reached, and recursion depth not exceeded, we judge this as a success and
+745              // stop the recursive call chain
+746              runCompleted.close();
+747              return;
+748            }
+749
+750            // request more right away, the Publisher must break the recursion
+751            subscription.value().request(1);
+752
+753            stackDepthCounter.set(stackDepthCounter.get() - 1);
+754          }
+755
+756          @Override
+757          public void onComplete() {
+758            super.onComplete();
+759            runCompleted.close();
+760          }
+761
+762          @Override
+763          public void onError(Throwable cause) {
+764            super.onError(cause);
+765            runCompleted.close();
+766          }
+767        };
+768
+769        try {
+770          env.subscribe(pub, sub);
+771
+772          sub.request(1); // kick-off the `request -> onNext -> request -> onNext -> ...`
+773
+774          final String msg = String.format("Unable to validate call stack depth safety, " +
+775                                               "awaited at-most %s signals (`maxOnNextSignalsInRecursionTest()`) or completion",
+776                                           oneMoreThanBoundedLimit);
+777          runCompleted.expectClose(env.defaultTimeoutMillis(), msg);
+778          env.verifyNoAsyncErrorsNoDelay();
+779        } finally {
+780          // since the request/onNext recursive calls may keep the publisher running "forever",
+781          // we MUST cancel it manually before exiting this test case
+782          sub.cancel();
+783        }
+784      }
+785    });
+786  }
+787
+788  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.4
+789  @Override @Test
+790  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+791    notVerified(); // cannot be meaningfully tested, or can it?
+792  }
+793
+794  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.5
+795  @Override @Test
+796  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() throws Exception {
+797    notVerified(); // cannot be meaningfully tested, or can it?
+798  }
+799
+800  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.6
+801  @Override @Test
+802  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+803    activePublisherTest(3, false, new PublisherTestRun<T>() {
+804      @Override
+805      public void run(Publisher<T> pub) throws Throwable {
+806
+807        // override ManualSubscriberWithSubscriptionSupport#cancel because by default a ManualSubscriber will drop the
+808        // subscription once it's cancelled (as expected).
+809        // In this test however it must keep the cancelled Subscription and keep issuing `request(long)` to it.
+810        ManualSubscriber<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+811          @Override
+812          public void cancel() {
+813            if (subscription.isCompleted()) {
+814              subscription.value().cancel();
+815            } else {
+816              env.flop("Cannot cancel a subscription before having received it");
+817            }
+818          }
+819        };
+820
+821        env.subscribe(pub, sub);
+822
+823        sub.cancel();
+824        sub.request(1);
+825        sub.request(1);
+826        sub.request(1);
+827
+828        sub.expectNone();
+829        env.verifyNoAsyncErrorsNoDelay();
+830      }
+831    });
+832  }
+833
+834  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.7
+835  @Override @Test
+836  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+837    activePublisherTest(1, false, new PublisherTestRun<T>() {
+838      @Override
+839      public void run(Publisher<T> pub) throws Throwable {
+840        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+841
+842        // leak the Subscription
+843        final Subscription subs = sub.subscription.value();
+844
+845        subs.cancel();
+846        subs.cancel();
+847        subs.cancel();
+848
+849        sub.expectNone();
+850        env.verifyNoAsyncErrorsNoDelay();
+851      }
+852    });
+853  }
+854
+855  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.9
+856  @Override @Test
+857  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+858    activePublisherTest(10, false, new PublisherTestRun<T>() {
+859      @Override public void run(Publisher<T> pub) throws Throwable {
+860        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+861        sub.request(0);
+862        sub.expectErrorWithMessage(IllegalArgumentException.class, "3.9"); // we do require implementations to mention the rule number at the very least
+863      }
+864    });
+865  }
+866
+867  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.9
+868  @Override @Test
+869  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+870    activePublisherTest(10, false, new PublisherTestRun<T>() {
+871      @Override
+872      public void run(Publisher<T> pub) throws Throwable {
+873        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+874        final Random r = new Random();
+875        sub.request(-r.nextInt(Integer.MAX_VALUE));
+876        sub.expectErrorWithMessage(IllegalArgumentException.class, "3.9"); // we do require implementations to mention the rule number at the very least
+877      }
+878    });
+879  }
+880
+881  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.12
+882  @Override @Test
+883  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+884    // the publisher is able to signal more elements than the subscriber will be requesting in total
+885    final int publisherElements = 20;
+886
+887    final int demand1 = 10;
+888    final int demand2 = 5;
+889    final int totalDemand = demand1 + demand2;
+890
+891    activePublisherTest(publisherElements, false, new PublisherTestRun<T>() {
+892      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+893      public void run(Publisher<T> pub) throws Throwable {
+894        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+895
+896        sub.request(demand1);
+897        sub.request(demand2);
+898
+899        /*
+900          NOTE: The order of the nextElement/cancel calls below is very important (!)
+901
+902          If this ordering was reversed, given an asynchronous publisher,
+903          the following scenario would be *legal* and would break this test:
+904
+905          > AsyncPublisher receives request(10) - it does not emit data right away, it's asynchronous
+906          > AsyncPublisher receives request(5) - demand is now 15
+907          ! AsyncPublisher didn't emit any onNext yet (!)
+908          > AsyncPublisher receives cancel() - handles it right away, by "stopping itself" for example
+909          ! cancel was handled hefore the AsyncPublisher ever got the chance to emit data
+910          ! the subscriber ends up never receiving even one element - the test is stuck (and fails, even on valid Publisher)
+911
+912          Which is why we must first expect an element, and then cancel, once the producing is "running".
+913         */
+914        sub.nextElement();
+915        sub.cancel();
+916
+917        int onNextsSignalled = 1;
+918
+919        boolean stillBeingSignalled;
+920        do {
+921          // put asyncError if onNext signal received
+922          sub.expectNone();
+923          Throwable error = env.dropAsyncError();
+924
+925          if (error == null) {
+926            stillBeingSignalled = false;
+927          } else {
+928            onNextsSignalled += 1;
+929            stillBeingSignalled = true;
+930          }
+931
+932          // if the Publisher tries to emit more elements than was requested (and/or ignores cancellation) this will throw
+933          assertTrue(onNextsSignalled <= totalDemand,
+934                     String.format("Publisher signalled [%d] elements, which is more than the signalled demand: %d",
+935                                   onNextsSignalled, totalDemand));
+936
+937        } while (stillBeingSignalled);
+938      }
+939    });
+940
+941    env.verifyNoAsyncErrorsNoDelay();
+942  }
+943
+944  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.13
+945  @Override @Test
+946  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+947    final ReferenceQueue<ManualSubscriber<T>> queue = new ReferenceQueue<ManualSubscriber<T>>();
+948
+949    final Function<Publisher<T>, WeakReference<ManualSubscriber<T>>> run = new Function<Publisher<T>, WeakReference<ManualSubscriber<T>>>() {
+950      @Override
+951      public WeakReference<ManualSubscriber<T>> apply(Publisher<T> pub) throws Exception {
+952        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+953        final WeakReference<ManualSubscriber<T>> ref = new WeakReference<ManualSubscriber<T>>(sub, queue);
+954
+955        sub.request(1);
+956        sub.nextElement();
+957        sub.cancel();
+958
+959        return ref;
+960      }
+961    };
+962
+963    activePublisherTest(3, false, new PublisherTestRun<T>() {
+964      @Override
+965      public void run(Publisher<T> pub) throws Throwable {
+966        final WeakReference<ManualSubscriber<T>> ref = run.apply(pub);
+967
+968        // cancel may be run asynchronously so we add a sleep before running the GC
+969        // to "resolve" the race
+970        Thread.sleep(publisherReferenceGCTimeoutMillis);
+971        System.gc();
+972
+973        if (!ref.equals(queue.remove(100))) {
+974          env.flop(String.format("Publisher %s did not drop reference to test subscriber after subscription cancellation", pub));
+975        }
+976
+977        env.verifyNoAsyncErrorsNoDelay();
+978      }
+979    });
+980  }
+981
+982  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.17
+983  @Override @Test
+984  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+985    final int totalElements = 3;
+986
+987    activePublisherTest(totalElements, true, new PublisherTestRun<T>() {
+988      @Override
+989      public void run(Publisher<T> pub) throws Throwable {
+990        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+991        sub.request(Long.MAX_VALUE);
+992
+993        sub.nextElements(totalElements);
+994        sub.expectCompletion();
+995
+996        env.verifyNoAsyncErrorsNoDelay();
+997      }
+998    });
+999  }
+1000
+1001  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.17
+1002  @Override @Test
+1003  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+1004    final int totalElements = 3;
+1005
+1006    activePublisherTest(totalElements, true, new PublisherTestRun<T>() {
+1007      @Override
+1008      public void run(Publisher<T> pub) throws Throwable {
+1009        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+1010        sub.request(Long.MAX_VALUE / 2); // pending = Long.MAX_VALUE / 2
+1011        sub.request(Long.MAX_VALUE / 2); // pending = Long.MAX_VALUE - 1
+1012        sub.request(1); // pending = Long.MAX_VALUE
+1013
+1014        sub.nextElements(totalElements);
+1015        sub.expectCompletion();
+1016
+1017        try {
+1018          env.verifyNoAsyncErrorsNoDelay();
+1019        } finally {
+1020          sub.cancel();
+1021        }
+1022        
+1023      }
+1024    });
+1025  }
+1026
+1027  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.17
+1028  @Override @Test
+1029  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+1030    activePublisherTest(Integer.MAX_VALUE, false, new PublisherTestRun<T>() {
+1031      @Override public void run(Publisher<T> pub) throws Throwable {
+1032        final ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(env) {
+1033           // arbitrarily set limit on nuber of request calls signalled, we expect overflow after already 2 calls,
+1034           // so 10 is relatively high and safe even if arbitrarily chosen
+1035          int callsCounter = 10;
+1036
+1037          @Override
+1038          public void onNext(T element) {
+1039            env.debug(String.format("%s::onNext(%s)", this, element));
+1040            if (subscription.isCompleted()) {
+1041              if (callsCounter > 0) {
+1042                subscription.value().request(Long.MAX_VALUE - 1);
+1043                callsCounter--;
+1044              } else {
+1045                  subscription.value().cancel();
+1046              }
+1047            } else {
+1048              env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+1049            }
+1050          }
+1051        };
+1052        env.subscribe(pub, sub, env.defaultTimeoutMillis());
+1053
+1054        // eventually triggers `onNext`, which will then trigger up to `callsCounter` times `request(Long.MAX_VALUE - 1)`
+1055        // we're pretty sure to overflow from those
+1056        sub.request(1);
+1057
+1058        // no onError should be signalled
+1059        try {
+1060          env.verifyNoAsyncErrors(env.defaultTimeoutMillis());
+1061        } finally {
+1062          sub.cancel();
+1063        }
+1064      }
+1065    });
+1066  }
+1067
+1068  ///////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+1069
+1070  ///////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+1071
+1072  public interface PublisherTestRun<T> {
+1073    public void run(Publisher<T> pub) throws Throwable;
+1074  }
+1075
+1076  /**
+1077   * Test for feature that SHOULD/MUST be implemented, using a live publisher.
+1078   *
+1079   * @param elements the number of elements the Publisher under test  must be able to emit to run this test
+1080   * @param completionSignalRequired true if an {@code onComplete} signal is required by this test to run.
+1081   *                                 If the tested Publisher is unable to signal completion, tests requireing onComplete signals will be skipped.
+1082   *                                 To signal if your Publisher is able to signal completion see {@link PublisherVerification#maxElementsFromPublisher()}.
+1083   */
+1084  public void activePublisherTest(long elements, boolean completionSignalRequired, PublisherTestRun<T> body) throws Throwable {
+1085    if (elements > maxElementsFromPublisher()) {
+1086      throw new SkipException(String.format("Unable to run this test, as required elements nr: %d is higher than supported by given producer: %d", elements, maxElementsFromPublisher()));
+1087    } else if (completionSignalRequired && maxElementsFromPublisher() == Long.MAX_VALUE) {
+1088      throw new SkipException("Unable to run this test, as it requires an onComplete signal, " +
+1089                                "which this Publisher is unable to provide (as signalled by returning Long.MAX_VALUE from `maxElementsFromPublisher()`)");
+1090    } else {
+1091      Publisher<T> pub = createPublisher(elements);
+1092      body.run(pub);
+1093      env.verifyNoAsyncErrorsNoDelay();
+1094    }
+1095  }
+1096
+1097  /**
+1098   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+1099   *
+1100   * @param elements the number of elements the Publisher under test  must be able to emit to run this test
+1101   * @param completionSignalRequired true if an {@code onComplete} signal is required by this test to run.
+1102   *                                 If the tested Publisher is unable to signal completion, tests requireing onComplete signals will be skipped.
+1103   *                                 To signal if your Publisher is able to signal completion see {@link PublisherVerification#maxElementsFromPublisher()}.
+1104   */
+1105  public void optionalActivePublisherTest(long elements, boolean completionSignalRequired, PublisherTestRun<T> body) throws Throwable {
+1106    if (elements > maxElementsFromPublisher()) {
+1107      throw new SkipException(String.format("Unable to run this test, as required elements nr: %d is higher than supported by given producer: %d", elements, maxElementsFromPublisher()));
+1108    } else if (completionSignalRequired && maxElementsFromPublisher() == Long.MAX_VALUE) {
+1109      throw new SkipException("Unable to run this test, as it requires an onComplete signal, " +
+1110                                "which this Publisher is unable to provide (as signalled by returning Long.MAX_VALUE from `maxElementsFromPublisher()`)");
+1111    } else {
+1112
+1113      final Publisher<T> pub = createPublisher(elements);
+1114      final String skipMessage = "Skipped because tested publisher does NOT implement this OPTIONAL requirement.";
+1115
+1116      try {
+1117        potentiallyPendingTest(pub, body);
+1118      } catch (Exception ex) {
+1119        notVerified(skipMessage);
+1120      } catch (AssertionError ex) {
+1121        notVerified(skipMessage + " Reason for skipping was: " + ex.getMessage());
+1122      }
+1123    }
+1124  }
+1125
+1126  public static final String SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE =
+1127    "Skipping because no error state Publisher provided, and the test requires it. " +
+1128          "Please implement PublisherVerification#createFailedPublisher to run this test.";
+1129
+1130  public static final String SKIPPING_OPTIONAL_TEST_FAILED =
+1131    "Skipping, because provided Publisher does not pass this *additional* verification.";
+1132  /**
+1133   * Additional test for Publisher in error state
+1134   */
+1135  public void whenHasErrorPublisherTest(PublisherTestRun<T> body) throws Throwable {
+1136    potentiallyPendingTest(createFailedPublisher(), body, SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE);
+1137  }
+1138
+1139  public void potentiallyPendingTest(Publisher<T> pub, PublisherTestRun<T> body) throws Throwable {
+1140    potentiallyPendingTest(pub, body, SKIPPING_OPTIONAL_TEST_FAILED);
+1141  }
+1142
+1143  public void potentiallyPendingTest(Publisher<T> pub, PublisherTestRun<T> body, String message) throws Throwable {
+1144    if (pub != null) {
+1145      body.run(pub);
+1146    } else {
+1147      throw new SkipException(message);
+1148    }
+1149  }
+1150
+1151  /**
+1152   * Executes a given test body {@code n} times.
+1153   * All the test runs must pass in order for the stochastic test to pass.
+1154   */
+1155  public void stochasticTest(int n, Function<Integer, Void> body) throws Throwable {
+1156    if (skipStochasticTests()) {
+1157      notVerified("Skipping @Stochastic test because `skipStochasticTests()` returned `true`!");
+1158    }
+1159
+1160    for (int i = 0; i < n; i++) {
+1161      body.apply(i);
+1162    }
+1163  }
+1164
+1165  public void notVerified() {
+1166    throw new SkipException("Not verified by this TCK.");
+1167  }
+1168
+1169  /**
+1170   * Return this value from {@link PublisherVerification#maxElementsFromPublisher()} to mark that the given {@link org.reactivestreams.Publisher},
+1171   * is not able to signal completion. For example it is strictly a time-bound or unbounded source of data.
+1172   *
+1173   * <b>Returning this value from {@link PublisherVerification#maxElementsFromPublisher()} will result in skipping all TCK tests which require onComplete signals!</b>
+1174   */
+1175  public long publisherUnableToSignalOnComplete() {
+1176    return Long.MAX_VALUE;
+1177  }
+1178
+1179  public void notVerified(String message) {
+1180    throw new SkipException(message);
+1181  }
+1182
+1183}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html new file mode 100644 index 0000000..cdb9196 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.BlackboxTestStage.html @@ -0,0 +1,596 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+007import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+008import org.reactivestreams.tck.support.Optional;
+009import org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules;
+010import org.reactivestreams.tck.support.TestException;
+011import org.testng.SkipException;
+012import org.testng.annotations.AfterClass;
+013import org.testng.annotations.BeforeClass;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.util.concurrent.ExecutorService;
+018import java.util.concurrent.Executors;
+019
+020import static org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy;
+021import static org.testng.Assert.assertTrue;
+022
+023/**
+024 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription}
+025 * specification rules, without any modifications to the tested implementation (also known as "Black Box" testing).
+026 *
+027 * This verification is NOT able to check many of the rules of the spec, and if you want more
+028 * verification of your implementation you'll have to implement {@code org.reactivestreams.tck.SubscriberWhiteboxVerification}
+029 * instead.
+030 *
+031 * @see org.reactivestreams.Subscriber
+032 * @see org.reactivestreams.Subscription
+033 */
+034public abstract class SubscriberBlackboxVerification<T> extends WithHelperPublisher<T> 
+035  implements SubscriberBlackboxVerificationRules {
+036
+037  protected final TestEnvironment env;
+038
+039  protected SubscriberBlackboxVerification(TestEnvironment env) {
+040    this.env = env;
+041  }
+042
+043  // USER API
+044
+045  /**
+046   * This is the main method you must implement in your test incarnation.
+047   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+048   */
+049  public abstract Subscriber<T> createSubscriber();
+050
+051  /**
+052   * Override this method if the Subscriber implementation you are verifying
+053   * needs an external signal before it signals demand to its Publisher.
+054   *
+055   * By default this method does nothing.
+056   */
+057  public void triggerRequest(final Subscriber<? super T> subscriber) {
+058
+059  }
+060
+061  // ENV SETUP
+062
+063  /**
+064   * Executor service used by the default provided asynchronous Publisher.
+065   * @see #createHelperPublisher(long)
+066   */
+067  private ExecutorService publisherExecutor;
+068  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+069  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+070  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+071
+072  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+073
+074  @BeforeMethod
+075  public void setUp() throws Exception {
+076    env.clearAsyncErrors();
+077  }
+078
+079  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+080
+081  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+082  @Override @Test
+083  public void required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+084    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+085      @Override
+086      public void run(BlackboxTestStage stage) throws InterruptedException {
+087        triggerRequest(stage.subProxy().sub());
+088        final long n = stage.expectRequest();// assuming subscriber wants to consume elements...
+089
+090        // should cope with up to requested number of elements
+091        for (int i = 0; i < n; i++)
+092          stage.signalNext();
+093      }
+094    });
+095  }
+096
+097  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+098  @Override @Test
+099  public void untested_spec202_blackbox_shouldAsynchronouslyDispatch() throws Exception {
+100    notVerified(); // cannot be meaningfully tested, or can it?
+101  }
+102
+103  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+104  @Override @Test
+105  public void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+106    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+107      @Override
+108      public void run(BlackboxTestStage stage) throws Throwable {
+109        final Subscription subs = new Subscription() {
+110          @Override
+111          public void request(long n) {
+112            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+113            if (onCompleteStackTraceElement.isDefined()) {
+114              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+115              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+116                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+117            }
+118          }
+119
+120          @Override
+121          public void cancel() {
+122            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+123            if (onCompleteStackElement.isDefined()) {
+124              final StackTraceElement stackElem = onCompleteStackElement.get();
+125              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+126                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+127            }
+128          }
+129        };
+130
+131        final Subscriber<T> sub = createSubscriber();
+132        sub.onSubscribe(subs);
+133        sub.onComplete();
+134
+135        env.verifyNoAsyncErrorsNoDelay();
+136      }
+137    });
+138  }
+139
+140  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+141  @Override @Test
+142  public void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+143    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+144      @Override
+145      public void run(BlackboxTestStage stage) throws Throwable {
+146        final Subscription subs = new Subscription() {
+147          @Override
+148          public void request(long n) {
+149            Throwable thr = new Throwable();
+150            for (StackTraceElement stackElem : thr.getStackTrace()) {
+151              if (stackElem.getMethodName().equals("onError")) {
+152                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+153                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+154              }
+155            }
+156          }
+157
+158          @Override
+159          public void cancel() {
+160            Throwable thr = new Throwable();
+161            for (StackTraceElement stackElem : thr.getStackTrace()) {
+162              if (stackElem.getMethodName().equals("onError")) {
+163                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+164                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+165              }
+166            }
+167          }
+168        };
+169
+170        final Subscriber<T> sub = createSubscriber();
+171        sub.onSubscribe(subs);
+172        sub.onError(new TestException());
+173
+174        env.verifyNoAsyncErrorsNoDelay();
+175      }
+176    });
+177  }
+178
+179  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+180  @Override @Test
+181  public void untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+182    notVerified(); // cannot be meaningfully tested, or can it?
+183  }
+184
+185  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+186  @Override @Test
+187  public void required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Exception {
+188    new BlackboxTestStage(env) {{
+189      // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+190      final TestEnvironment.Latch secondSubscriptionCancelled = new TestEnvironment.Latch(env);
+191      sub().onSubscribe(
+192          new Subscription() {
+193            @Override
+194            public void request(long elements) {
+195              env.flop(String.format("Subscriber %s illegally called `subscription.request(%s)`!", sub(), elements));
+196            }
+197
+198            @Override
+199            public void cancel() {
+200              secondSubscriptionCancelled.close();
+201            }
+202
+203            @Override
+204            public String toString() {
+205              return "SecondSubscription(should get cancelled)";
+206            }
+207          });
+208
+209      secondSubscriptionCancelled.expectClose("Expected SecondSubscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called.");
+210      env.verifyNoAsyncErrorsNoDelay();
+211    }};
+212  }
+213
+214  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+215  @Override @Test
+216  public void untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+217    notVerified(); // cannot be meaningfully tested, or can it?
+218  }
+219
+220  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+221  @Override @Test
+222  public void untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+223    notVerified(); // cannot be meaningfully tested, or can it?
+224    // the same thread part of the clause can be verified but that is not very useful, or is it?
+225  }
+226
+227  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+228  @Override @Test
+229  public void untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+230    notVerified(); // cannot be meaningfully tested as black box, or can it?
+231  }
+232
+233  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+234  @Override @Test
+235  public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+236    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+237      @Override
+238      public void run(BlackboxTestStage stage) throws Throwable {
+239        final Publisher<T> pub = new Publisher<T>() {
+240          @Override public void subscribe(final Subscriber<? super T> s) {
+241            s.onSubscribe(new Subscription() {
+242              private boolean completed = false;
+243
+244              @Override public void request(long n) {
+245                if (!completed) {
+246                  completed = true;
+247                  s.onComplete(); // Publisher now realises that it is in fact already completed
+248                }
+249              }
+250
+251              @Override public void cancel() {
+252                // noop, ignore
+253              }
+254            });
+255          }
+256        };
+257
+258        final Subscriber<T> sub = createSubscriber();
+259        final BlackboxSubscriberProxy<T> probe = stage.createBlackboxSubscriberProxy(env, sub);
+260
+261        pub.subscribe(probe);
+262        triggerRequest(sub);
+263        probe.expectCompletion();
+264        probe.expectNone();
+265
+266        env.verifyNoAsyncErrorsNoDelay();
+267      }
+268    });
+269  }
+270
+271  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+272  @Override @Test
+273  public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+274    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+275      @Override
+276      public void run(BlackboxTestStage stage) throws Throwable {
+277        final Publisher<T> pub = new Publisher<T>() {
+278          @Override
+279          public void subscribe(Subscriber<? super T> s) {
+280            s.onComplete();
+281          }
+282        };
+283
+284        final Subscriber<T> sub = createSubscriber();
+285        final BlackboxSubscriberProxy<T> probe = stage.createBlackboxSubscriberProxy(env, sub);
+286
+287        pub.subscribe(probe);
+288        probe.expectCompletion();
+289
+290        env.verifyNoAsyncErrorsNoDelay();
+291      }
+292    });
+293  }
+294
+295  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+296  @Override @Test
+297  public void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+298    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+299      @Override
+300      @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+301      public void run(BlackboxTestStage stage) throws Throwable {
+302        stage.sub().onError(new TestException());
+303        stage.subProxy().expectError(Throwable.class);
+304      }
+305    });
+306  }
+307
+308  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+309  @Override @Test
+310  public void untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+311    notVerified(); // cannot be meaningfully tested, or can it?
+312  }
+313
+314  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+315  @Override @Test
+316  public void untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() throws Throwable {
+317    notVerified(); // cannot be meaningfully tested as black box, or can it?
+318  }
+319
+320  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+321  @Override @Test
+322  public void untested_spec213_blackbox_failingOnSignalInvocation() throws Exception {
+323    notVerified(); // cannot be meaningfully tested, or can it?
+324  }
+325
+326  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+327  @Override @Test
+328  public void required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+329    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+330      @Override
+331      public void run(BlackboxTestStage stage) throws Throwable {
+332
+333        {
+334          final Subscriber<T> sub = createSubscriber();
+335          boolean gotNPE = false;
+336          try {
+337            sub.onSubscribe(null);
+338          } catch(final NullPointerException expected) {
+339            gotNPE = true;
+340          }
+341          assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+342        }
+343
+344        env.verifyNoAsyncErrorsNoDelay();
+345      }
+346    });
+347  }
+348
+349  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+350  @Override @Test
+351  public void required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+352    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+353      @Override
+354      public void run(BlackboxTestStage stage) throws Throwable {
+355        final Subscription subscription = new Subscription() {
+356          @Override public void request(final long elements) {}
+357          @Override public void cancel() {}
+358        };
+359
+360        {
+361          final Subscriber<T> sub = createSubscriber();
+362          boolean gotNPE = false;
+363          sub.onSubscribe(subscription);
+364          try {
+365            sub.onNext(null);
+366          } catch(final NullPointerException expected) {
+367            gotNPE = true;
+368          }
+369          assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+370        }
+371
+372        env.verifyNoAsyncErrorsNoDelay();
+373      }
+374    });
+375  }
+376
+377  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+378  @Override @Test
+379  public void required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+380    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+381      @Override
+382      public void run(BlackboxTestStage stage) throws Throwable {
+383        final Subscription subscription = new Subscription() {
+384          @Override public void request(final long elements) {}
+385          @Override public void cancel() {}
+386        };
+387
+388        {
+389          final Subscriber<T> sub = createSubscriber();
+390          boolean gotNPE = false;
+391          sub.onSubscribe(subscription);
+392          try {
+393            sub.onError(null);
+394          } catch(final NullPointerException expected) {
+395            gotNPE = true;
+396          }
+397          assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+398        }
+399
+400        env.verifyNoAsyncErrorsNoDelay();
+401      }
+402    });
+403  }
+404
+405  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+406
+407  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+408  @Override @Test
+409  public void untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+410    notVerified(); // cannot be meaningfully tested, or can it?
+411  }
+412
+413  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+414  @Override @Test
+415  public void untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+416    notVerified(); // cannot be meaningfully tested as black box, or can it?
+417  }
+418
+419  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+420  @Override @Test
+421  public void untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+422    notVerified(); // cannot be meaningfully tested, or can it?
+423  }
+424
+425  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+426  @Override @Test
+427  public void untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+428    notVerified(); // cannot be meaningfully tested, or can it?
+429  }
+430
+431  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+432  @Override @Test
+433  public void untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+434    notVerified(); // cannot be meaningfully tested, or can it?
+435  }
+436
+437  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+438  @Override @Test
+439  public void untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+440    notVerified(); // cannot be meaningfully tested, or can it?
+441  }
+442
+443  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+444  @Override @Test
+445  public void untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+446    notVerified(); // cannot be meaningfully tested, or can it?
+447  }
+448
+449  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+450
+451  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+452
+453  abstract class BlackboxTestStageTestRun {
+454    public abstract void run(BlackboxTestStage stage) throws Throwable;
+455  }
+456
+457  public void blackboxSubscriberTest(BlackboxTestStageTestRun body) throws Throwable {
+458    BlackboxTestStage stage = new BlackboxTestStage(env, true);
+459    body.run(stage);
+460  }
+461
+462  public void blackboxSubscriberWithoutSetupTest(BlackboxTestStageTestRun body) throws Throwable {
+463    BlackboxTestStage stage = new BlackboxTestStage(env, false);
+464    body.run(stage);
+465  }
+466
+467  public class BlackboxTestStage extends ManualPublisher<T> {
+468    public Publisher<T> pub;
+469    public ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+470
+471    public T lastT = null;
+472    private Optional<BlackboxSubscriberProxy<T>> subProxy = Optional.empty();
+473
+474    public BlackboxTestStage(TestEnvironment env) throws InterruptedException {
+475      this(env, true);
+476    }
+477
+478    public BlackboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+479      super(env);
+480      if (runDefaultInit) {
+481        pub = this.createHelperPublisher(Long.MAX_VALUE);
+482        tees = env.newManualSubscriber(pub);
+483        Subscriber<T> sub = createSubscriber();
+484        subProxy = Optional.of(createBlackboxSubscriberProxy(env, sub));
+485        subscribe(subProxy.get());
+486      }
+487    }
+488
+489    public Subscriber<? super T> sub() {
+490      return subscriber.value();
+491    }
+492
+493    /**
+494     * Proxy for the {@link #sub()} {@code Subscriber}, providing certain assertions on methods being called on the Subscriber.
+495     */
+496    public BlackboxSubscriberProxy<T> subProxy() {
+497      return subProxy.get();
+498    }
+499
+500    public Publisher<T> createHelperPublisher(long elements) {
+501      return SubscriberBlackboxVerification.this.createHelperPublisher(elements);
+502    }
+503
+504    public BlackboxSubscriberProxy<T> createBlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> sub) {
+505      return new BlackboxSubscriberProxy<T>(env, sub);
+506    }
+507
+508    public T signalNext() throws InterruptedException {
+509      T element = nextT();
+510      sendNext(element);
+511      return element;
+512    }
+513
+514    public T nextT() throws InterruptedException {
+515      lastT = tees.requestNextElement();
+516      return lastT;
+517    }
+518
+519  }
+520
+521  public void notVerified() {
+522    throw new SkipException("Not verified using this TCK.");
+523  }
+524}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.html new file mode 100644 index 0000000..cdb9196 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberBlackboxVerification.html @@ -0,0 +1,596 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+007import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+008import org.reactivestreams.tck.support.Optional;
+009import org.reactivestreams.tck.support.SubscriberBlackboxVerificationRules;
+010import org.reactivestreams.tck.support.TestException;
+011import org.testng.SkipException;
+012import org.testng.annotations.AfterClass;
+013import org.testng.annotations.BeforeClass;
+014import org.testng.annotations.BeforeMethod;
+015import org.testng.annotations.Test;
+016
+017import java.util.concurrent.ExecutorService;
+018import java.util.concurrent.Executors;
+019
+020import static org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy;
+021import static org.testng.Assert.assertTrue;
+022
+023/**
+024 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription}
+025 * specification rules, without any modifications to the tested implementation (also known as "Black Box" testing).
+026 *
+027 * This verification is NOT able to check many of the rules of the spec, and if you want more
+028 * verification of your implementation you'll have to implement {@code org.reactivestreams.tck.SubscriberWhiteboxVerification}
+029 * instead.
+030 *
+031 * @see org.reactivestreams.Subscriber
+032 * @see org.reactivestreams.Subscription
+033 */
+034public abstract class SubscriberBlackboxVerification<T> extends WithHelperPublisher<T> 
+035  implements SubscriberBlackboxVerificationRules {
+036
+037  protected final TestEnvironment env;
+038
+039  protected SubscriberBlackboxVerification(TestEnvironment env) {
+040    this.env = env;
+041  }
+042
+043  // USER API
+044
+045  /**
+046   * This is the main method you must implement in your test incarnation.
+047   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+048   */
+049  public abstract Subscriber<T> createSubscriber();
+050
+051  /**
+052   * Override this method if the Subscriber implementation you are verifying
+053   * needs an external signal before it signals demand to its Publisher.
+054   *
+055   * By default this method does nothing.
+056   */
+057  public void triggerRequest(final Subscriber<? super T> subscriber) {
+058
+059  }
+060
+061  // ENV SETUP
+062
+063  /**
+064   * Executor service used by the default provided asynchronous Publisher.
+065   * @see #createHelperPublisher(long)
+066   */
+067  private ExecutorService publisherExecutor;
+068  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+069  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+070  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+071
+072  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+073
+074  @BeforeMethod
+075  public void setUp() throws Exception {
+076    env.clearAsyncErrors();
+077  }
+078
+079  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+080
+081  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+082  @Override @Test
+083  public void required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+084    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+085      @Override
+086      public void run(BlackboxTestStage stage) throws InterruptedException {
+087        triggerRequest(stage.subProxy().sub());
+088        final long n = stage.expectRequest();// assuming subscriber wants to consume elements...
+089
+090        // should cope with up to requested number of elements
+091        for (int i = 0; i < n; i++)
+092          stage.signalNext();
+093      }
+094    });
+095  }
+096
+097  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+098  @Override @Test
+099  public void untested_spec202_blackbox_shouldAsynchronouslyDispatch() throws Exception {
+100    notVerified(); // cannot be meaningfully tested, or can it?
+101  }
+102
+103  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+104  @Override @Test
+105  public void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+106    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+107      @Override
+108      public void run(BlackboxTestStage stage) throws Throwable {
+109        final Subscription subs = new Subscription() {
+110          @Override
+111          public void request(long n) {
+112            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+113            if (onCompleteStackTraceElement.isDefined()) {
+114              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+115              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+116                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+117            }
+118          }
+119
+120          @Override
+121          public void cancel() {
+122            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+123            if (onCompleteStackElement.isDefined()) {
+124              final StackTraceElement stackElem = onCompleteStackElement.get();
+125              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+126                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+127            }
+128          }
+129        };
+130
+131        final Subscriber<T> sub = createSubscriber();
+132        sub.onSubscribe(subs);
+133        sub.onComplete();
+134
+135        env.verifyNoAsyncErrorsNoDelay();
+136      }
+137    });
+138  }
+139
+140  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+141  @Override @Test
+142  public void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+143    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+144      @Override
+145      public void run(BlackboxTestStage stage) throws Throwable {
+146        final Subscription subs = new Subscription() {
+147          @Override
+148          public void request(long n) {
+149            Throwable thr = new Throwable();
+150            for (StackTraceElement stackElem : thr.getStackTrace()) {
+151              if (stackElem.getMethodName().equals("onError")) {
+152                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+153                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+154              }
+155            }
+156          }
+157
+158          @Override
+159          public void cancel() {
+160            Throwable thr = new Throwable();
+161            for (StackTraceElement stackElem : thr.getStackTrace()) {
+162              if (stackElem.getMethodName().equals("onError")) {
+163                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+164                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+165              }
+166            }
+167          }
+168        };
+169
+170        final Subscriber<T> sub = createSubscriber();
+171        sub.onSubscribe(subs);
+172        sub.onError(new TestException());
+173
+174        env.verifyNoAsyncErrorsNoDelay();
+175      }
+176    });
+177  }
+178
+179  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+180  @Override @Test
+181  public void untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+182    notVerified(); // cannot be meaningfully tested, or can it?
+183  }
+184
+185  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+186  @Override @Test
+187  public void required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Exception {
+188    new BlackboxTestStage(env) {{
+189      // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+190      final TestEnvironment.Latch secondSubscriptionCancelled = new TestEnvironment.Latch(env);
+191      sub().onSubscribe(
+192          new Subscription() {
+193            @Override
+194            public void request(long elements) {
+195              env.flop(String.format("Subscriber %s illegally called `subscription.request(%s)`!", sub(), elements));
+196            }
+197
+198            @Override
+199            public void cancel() {
+200              secondSubscriptionCancelled.close();
+201            }
+202
+203            @Override
+204            public String toString() {
+205              return "SecondSubscription(should get cancelled)";
+206            }
+207          });
+208
+209      secondSubscriptionCancelled.expectClose("Expected SecondSubscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called.");
+210      env.verifyNoAsyncErrorsNoDelay();
+211    }};
+212  }
+213
+214  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+215  @Override @Test
+216  public void untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+217    notVerified(); // cannot be meaningfully tested, or can it?
+218  }
+219
+220  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+221  @Override @Test
+222  public void untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+223    notVerified(); // cannot be meaningfully tested, or can it?
+224    // the same thread part of the clause can be verified but that is not very useful, or is it?
+225  }
+226
+227  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+228  @Override @Test
+229  public void untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+230    notVerified(); // cannot be meaningfully tested as black box, or can it?
+231  }
+232
+233  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+234  @Override @Test
+235  public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+236    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+237      @Override
+238      public void run(BlackboxTestStage stage) throws Throwable {
+239        final Publisher<T> pub = new Publisher<T>() {
+240          @Override public void subscribe(final Subscriber<? super T> s) {
+241            s.onSubscribe(new Subscription() {
+242              private boolean completed = false;
+243
+244              @Override public void request(long n) {
+245                if (!completed) {
+246                  completed = true;
+247                  s.onComplete(); // Publisher now realises that it is in fact already completed
+248                }
+249              }
+250
+251              @Override public void cancel() {
+252                // noop, ignore
+253              }
+254            });
+255          }
+256        };
+257
+258        final Subscriber<T> sub = createSubscriber();
+259        final BlackboxSubscriberProxy<T> probe = stage.createBlackboxSubscriberProxy(env, sub);
+260
+261        pub.subscribe(probe);
+262        triggerRequest(sub);
+263        probe.expectCompletion();
+264        probe.expectNone();
+265
+266        env.verifyNoAsyncErrorsNoDelay();
+267      }
+268    });
+269  }
+270
+271  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+272  @Override @Test
+273  public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+274    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+275      @Override
+276      public void run(BlackboxTestStage stage) throws Throwable {
+277        final Publisher<T> pub = new Publisher<T>() {
+278          @Override
+279          public void subscribe(Subscriber<? super T> s) {
+280            s.onComplete();
+281          }
+282        };
+283
+284        final Subscriber<T> sub = createSubscriber();
+285        final BlackboxSubscriberProxy<T> probe = stage.createBlackboxSubscriberProxy(env, sub);
+286
+287        pub.subscribe(probe);
+288        probe.expectCompletion();
+289
+290        env.verifyNoAsyncErrorsNoDelay();
+291      }
+292    });
+293  }
+294
+295  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+296  @Override @Test
+297  public void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+298    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+299      @Override
+300      @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+301      public void run(BlackboxTestStage stage) throws Throwable {
+302        stage.sub().onError(new TestException());
+303        stage.subProxy().expectError(Throwable.class);
+304      }
+305    });
+306  }
+307
+308  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+309  @Override @Test
+310  public void untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+311    notVerified(); // cannot be meaningfully tested, or can it?
+312  }
+313
+314  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+315  @Override @Test
+316  public void untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() throws Throwable {
+317    notVerified(); // cannot be meaningfully tested as black box, or can it?
+318  }
+319
+320  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+321  @Override @Test
+322  public void untested_spec213_blackbox_failingOnSignalInvocation() throws Exception {
+323    notVerified(); // cannot be meaningfully tested, or can it?
+324  }
+325
+326  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+327  @Override @Test
+328  public void required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+329    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+330      @Override
+331      public void run(BlackboxTestStage stage) throws Throwable {
+332
+333        {
+334          final Subscriber<T> sub = createSubscriber();
+335          boolean gotNPE = false;
+336          try {
+337            sub.onSubscribe(null);
+338          } catch(final NullPointerException expected) {
+339            gotNPE = true;
+340          }
+341          assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+342        }
+343
+344        env.verifyNoAsyncErrorsNoDelay();
+345      }
+346    });
+347  }
+348
+349  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+350  @Override @Test
+351  public void required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+352    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+353      @Override
+354      public void run(BlackboxTestStage stage) throws Throwable {
+355        final Subscription subscription = new Subscription() {
+356          @Override public void request(final long elements) {}
+357          @Override public void cancel() {}
+358        };
+359
+360        {
+361          final Subscriber<T> sub = createSubscriber();
+362          boolean gotNPE = false;
+363          sub.onSubscribe(subscription);
+364          try {
+365            sub.onNext(null);
+366          } catch(final NullPointerException expected) {
+367            gotNPE = true;
+368          }
+369          assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+370        }
+371
+372        env.verifyNoAsyncErrorsNoDelay();
+373      }
+374    });
+375  }
+376
+377  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+378  @Override @Test
+379  public void required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+380    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+381      @Override
+382      public void run(BlackboxTestStage stage) throws Throwable {
+383        final Subscription subscription = new Subscription() {
+384          @Override public void request(final long elements) {}
+385          @Override public void cancel() {}
+386        };
+387
+388        {
+389          final Subscriber<T> sub = createSubscriber();
+390          boolean gotNPE = false;
+391          sub.onSubscribe(subscription);
+392          try {
+393            sub.onError(null);
+394          } catch(final NullPointerException expected) {
+395            gotNPE = true;
+396          }
+397          assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+398        }
+399
+400        env.verifyNoAsyncErrorsNoDelay();
+401      }
+402    });
+403  }
+404
+405  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+406
+407  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+408  @Override @Test
+409  public void untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+410    notVerified(); // cannot be meaningfully tested, or can it?
+411  }
+412
+413  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+414  @Override @Test
+415  public void untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+416    notVerified(); // cannot be meaningfully tested as black box, or can it?
+417  }
+418
+419  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+420  @Override @Test
+421  public void untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+422    notVerified(); // cannot be meaningfully tested, or can it?
+423  }
+424
+425  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+426  @Override @Test
+427  public void untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+428    notVerified(); // cannot be meaningfully tested, or can it?
+429  }
+430
+431  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+432  @Override @Test
+433  public void untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+434    notVerified(); // cannot be meaningfully tested, or can it?
+435  }
+436
+437  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+438  @Override @Test
+439  public void untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+440    notVerified(); // cannot be meaningfully tested, or can it?
+441  }
+442
+443  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+444  @Override @Test
+445  public void untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+446    notVerified(); // cannot be meaningfully tested, or can it?
+447  }
+448
+449  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+450
+451  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+452
+453  abstract class BlackboxTestStageTestRun {
+454    public abstract void run(BlackboxTestStage stage) throws Throwable;
+455  }
+456
+457  public void blackboxSubscriberTest(BlackboxTestStageTestRun body) throws Throwable {
+458    BlackboxTestStage stage = new BlackboxTestStage(env, true);
+459    body.run(stage);
+460  }
+461
+462  public void blackboxSubscriberWithoutSetupTest(BlackboxTestStageTestRun body) throws Throwable {
+463    BlackboxTestStage stage = new BlackboxTestStage(env, false);
+464    body.run(stage);
+465  }
+466
+467  public class BlackboxTestStage extends ManualPublisher<T> {
+468    public Publisher<T> pub;
+469    public ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+470
+471    public T lastT = null;
+472    private Optional<BlackboxSubscriberProxy<T>> subProxy = Optional.empty();
+473
+474    public BlackboxTestStage(TestEnvironment env) throws InterruptedException {
+475      this(env, true);
+476    }
+477
+478    public BlackboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+479      super(env);
+480      if (runDefaultInit) {
+481        pub = this.createHelperPublisher(Long.MAX_VALUE);
+482        tees = env.newManualSubscriber(pub);
+483        Subscriber<T> sub = createSubscriber();
+484        subProxy = Optional.of(createBlackboxSubscriberProxy(env, sub));
+485        subscribe(subProxy.get());
+486      }
+487    }
+488
+489    public Subscriber<? super T> sub() {
+490      return subscriber.value();
+491    }
+492
+493    /**
+494     * Proxy for the {@link #sub()} {@code Subscriber}, providing certain assertions on methods being called on the Subscriber.
+495     */
+496    public BlackboxSubscriberProxy<T> subProxy() {
+497      return subProxy.get();
+498    }
+499
+500    public Publisher<T> createHelperPublisher(long elements) {
+501      return SubscriberBlackboxVerification.this.createHelperPublisher(elements);
+502    }
+503
+504    public BlackboxSubscriberProxy<T> createBlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> sub) {
+505      return new BlackboxSubscriberProxy<T>(env, sub);
+506    }
+507
+508    public T signalNext() throws InterruptedException {
+509      T element = nextT();
+510      sendNext(element);
+511      return element;
+512    }
+513
+514    public T nextT() throws InterruptedException {
+515      lastT = tees.requestNextElement();
+516      return lastT;
+517    }
+518
+519  }
+520
+521  public void notVerified() {
+522    throw new SkipException("Not verified using this TCK.");
+523  }
+524}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxProbe.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.BlackboxSubscriberProxy.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberProbe.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppet.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.SubscriberPuppeteer.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxSubscriberProbe.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.WhiteboxTestStage.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.html new file mode 100644 index 0000000..339d707 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/SubscriberWhiteboxVerification.html @@ -0,0 +1,857 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.TestEnvironment.*;
+007import org.reactivestreams.tck.support.Optional;
+008import org.reactivestreams.tck.support.SubscriberWhiteboxVerificationRules;
+009import org.reactivestreams.tck.support.TestException;
+010import org.testng.SkipException;
+011import org.testng.annotations.AfterClass;
+012import org.testng.annotations.BeforeClass;
+013import org.testng.annotations.BeforeMethod;
+014import org.testng.annotations.Test;
+015
+016import java.util.concurrent.ExecutorService;
+017import java.util.concurrent.Executors;
+018
+019import static org.testng.Assert.assertTrue;
+020
+021/**
+022 * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.Subscription} specification rules.
+023 *
+024 * @see org.reactivestreams.Subscriber
+025 * @see org.reactivestreams.Subscription
+026 */
+027public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+028  implements SubscriberWhiteboxVerificationRules {
+029
+030  private final TestEnvironment env;
+031
+032  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+033    this.env = env;
+034  }
+035
+036  // USER API
+037
+038  /**
+039   * This is the main method you must implement in your test incarnation.
+040   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+041   *
+042   * In order to be meaningfully testable your Subscriber must inform the given
+043   * `WhiteboxSubscriberProbe` of the respective events having been received.
+044   */
+045  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+046
+047  // ENV SETUP
+048
+049  /**
+050   * Executor service used by the default provided asynchronous Publisher.
+051   * @see #createHelperPublisher(long)
+052   */
+053  private ExecutorService publisherExecutor;
+054  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+055  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+056  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+057
+058  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+059
+060  @BeforeMethod
+061  public void setUp() throws Exception {
+062    env.clearAsyncErrors();
+063  }
+064
+065  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+066
+067  @Test
+068  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+069    subscriberTest(new TestStageTestRun() {
+070      @Override
+071      public void run(WhiteboxTestStage stage) throws InterruptedException {
+072        stage.puppet().triggerRequest(1);
+073        stage.puppet().triggerRequest(1);
+074
+075        long receivedRequests = stage.expectRequest();
+076
+077        stage.signalNext();
+078        stage.probe.expectNext(stage.lastT);
+079
+080        stage.puppet().triggerRequest(1);
+081        if (receivedRequests == 1) {
+082          stage.expectRequest();
+083        }
+084
+085        stage.signalNext();
+086        stage.probe.expectNext(stage.lastT);
+087
+088        stage.puppet().signalCancel();
+089        stage.expectCancelling();
+090
+091        stage.verifyNoAsyncErrors();
+092      }
+093    });
+094  }
+095
+096  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+097
+098  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+099  @Override @Test
+100  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+101    subscriberTest(new TestStageTestRun() {
+102      @Override
+103      public void run(WhiteboxTestStage stage) throws InterruptedException {
+104        stage.puppet().triggerRequest(1);
+105        stage.expectRequest();
+106
+107        stage.signalNext();
+108      }
+109    });
+110  }
+111
+112  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+113  @Override @Test
+114  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+115    notVerified(); // cannot be meaningfully tested, or can it?
+116  }
+117
+118  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+119  @Override @Test
+120  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+121    subscriberTestWithoutSetup(new TestStageTestRun() {
+122      @Override
+123      public void run(WhiteboxTestStage stage) throws Throwable {
+124        final Subscription subs = new Subscription() {
+125          @Override
+126          public void request(long n) {
+127            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+128            if (onCompleteStackTraceElement.isDefined()) {
+129              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+130              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+131                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+132            }
+133          }
+134
+135          @Override
+136          public void cancel() {
+137            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+138            if (onCompleteStackElement.isDefined()) {
+139              final StackTraceElement stackElem = onCompleteStackElement.get();
+140              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+141                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+142            }
+143          }
+144        };
+145
+146        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+147        final Subscriber<T> sub = createSubscriber(stage.probe);
+148
+149        sub.onSubscribe(subs);
+150        sub.onComplete();
+151
+152        env.verifyNoAsyncErrorsNoDelay();
+153      }
+154    });
+155  }
+156
+157  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+158  @Override @Test
+159  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+160    subscriberTestWithoutSetup(new TestStageTestRun() {
+161      @Override
+162      public void run(WhiteboxTestStage stage) throws Throwable {
+163        final Subscription subs = new Subscription() {
+164          @Override
+165          public void request(long n) {
+166            Throwable thr = new Throwable();
+167            for (StackTraceElement stackElem : thr.getStackTrace()) {
+168              if (stackElem.getMethodName().equals("onError")) {
+169                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+170                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+171              }
+172            }
+173          }
+174
+175          @Override
+176          public void cancel() {
+177            Throwable thr = new Throwable();
+178            for (StackTraceElement stackElem : thr.getStackTrace()) {
+179              if (stackElem.getMethodName().equals("onError")) {
+180                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+181                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+182              }
+183            }
+184          }
+185        };
+186
+187        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+188        final Subscriber<T> sub = createSubscriber(stage.probe);
+189
+190        sub.onSubscribe(subs);
+191        sub.onError(new TestException());
+192
+193        env.verifyNoAsyncErrorsNoDelay();
+194      }
+195    });
+196  }
+197
+198  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+199  @Override @Test
+200  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+201    notVerified(); // cannot be meaningfully tested, or can it?
+202  }
+203
+204  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+205  @Override @Test
+206  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+207    subscriberTest(new TestStageTestRun() {
+208      @Override
+209      public void run(WhiteboxTestStage stage) throws Throwable {
+210        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+211        final Latch secondSubscriptionCancelled = new Latch(env);
+212        final Subscriber<? super T> sub = stage.sub();
+213        final Subscription subscription = new Subscription() {
+214          @Override
+215          public void request(long elements) {
+216            // ignore...
+217          }
+218
+219          @Override
+220          public void cancel() {
+221            secondSubscriptionCancelled.close();
+222          }
+223
+224          @Override
+225          public String toString() {
+226            return "SecondSubscription(should get cancelled)";
+227          }
+228        };
+229        sub.onSubscribe(subscription);
+230
+231        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+232        env.verifyNoAsyncErrors();
+233      }
+234    });
+235  }
+236
+237  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+238  @Override @Test
+239  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+240    notVerified(); // cannot be meaningfully tested, or can it?
+241  }
+242
+243  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+244  @Override @Test
+245  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+246    notVerified(); // cannot be meaningfully tested, or can it?
+247    // the same thread part of the clause can be verified but that is not very useful, or is it?
+248  }
+249
+250  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+251  @Override @Test
+252  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+253    subscriberTest(new TestStageTestRun() {
+254      @Override
+255      public void run(WhiteboxTestStage stage) throws InterruptedException {
+256        stage.puppet().triggerRequest(1);
+257        stage.puppet().signalCancel();
+258        stage.signalNext();
+259
+260        stage.puppet().triggerRequest(1);
+261        stage.puppet().triggerRequest(1);
+262
+263        stage.verifyNoAsyncErrors();
+264      }
+265    });
+266  }
+267
+268  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+269  @Override @Test
+270  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+271    subscriberTest(new TestStageTestRun() {
+272      @Override
+273      public void run(WhiteboxTestStage stage) throws InterruptedException {
+274        stage.puppet().triggerRequest(1);
+275        stage.sendCompletion();
+276        stage.probe.expectCompletion();
+277
+278        stage.verifyNoAsyncErrors();
+279      }
+280    });
+281  }
+282
+283  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+284  @Override @Test
+285  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+286    subscriberTest(new TestStageTestRun() {
+287      @Override
+288      public void run(WhiteboxTestStage stage) throws InterruptedException {
+289        stage.sendCompletion();
+290        stage.probe.expectCompletion();
+291
+292        stage.verifyNoAsyncErrors();
+293      }
+294    });
+295  }
+296
+297  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+298  @Override @Test
+299  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+300    subscriberTest(new TestStageTestRun() {
+301      @Override
+302      public void run(WhiteboxTestStage stage) throws InterruptedException {
+303        stage.puppet().triggerRequest(1);
+304        stage.puppet().triggerRequest(1);
+305
+306        Exception ex = new TestException();
+307        stage.sendError(ex);
+308        stage.probe.expectError(ex);
+309
+310        env.verifyNoAsyncErrorsNoDelay();
+311      }
+312    });
+313  }
+314
+315  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+316  @Override @Test
+317  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+318    subscriberTest(new TestStageTestRun() {
+319      @Override
+320      public void run(WhiteboxTestStage stage) throws InterruptedException {
+321        Exception ex = new TestException();
+322        stage.sendError(ex);
+323        stage.probe.expectError(ex);
+324
+325        env.verifyNoAsyncErrorsNoDelay();
+326      }
+327    });
+328  }
+329
+330  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+331  @Override @Test
+332  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+333    notVerified(); // cannot be meaningfully tested, or can it?
+334  }
+335
+336  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+337  @Override @Test
+338  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+339    notVerified(); // cannot be meaningfully tested, or can it?
+340  }
+341
+342  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+343  @Override @Test
+344  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+345    notVerified(); // cannot be meaningfully tested, or can it?
+346  }
+347
+348  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+349  @Override @Test
+350  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+351    subscriberTest(new TestStageTestRun() {
+352      @Override
+353      public void run(WhiteboxTestStage stage) throws Throwable {
+354
+355        final Subscriber<? super T> sub = stage.sub();
+356        boolean gotNPE = false;
+357        try {
+358          sub.onSubscribe(null);
+359        } catch (final NullPointerException expected) {
+360          gotNPE = true;
+361        } 
+362
+363        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+364        env.verifyNoAsyncErrorsNoDelay();
+365      }
+366    });
+367  }
+368
+369  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+370  @Override @Test
+371  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+372    subscriberTest(new TestStageTestRun() {
+373      @Override
+374      public void run(WhiteboxTestStage stage) throws Throwable {
+375
+376        final Subscriber<? super T> sub = stage.sub();
+377        boolean gotNPE = false;
+378        try {
+379          sub.onNext(null);
+380        } catch (final NullPointerException expected) {
+381          gotNPE = true;
+382        }
+383
+384        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+385        env.verifyNoAsyncErrorsNoDelay();
+386      }
+387    });
+388  }
+389
+390  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+391  @Override @Test
+392  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+393    subscriberTest(new TestStageTestRun() {
+394      @Override
+395      public void run(WhiteboxTestStage stage) throws Throwable {
+396
+397          final Subscriber<? super T> sub = stage.sub();
+398          boolean gotNPE = false;
+399          try {
+400            sub.onError(null);
+401          } catch (final NullPointerException expected) {
+402            gotNPE = true;
+403          } finally {
+404            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+405          }
+406
+407        env.verifyNoAsyncErrorsNoDelay();
+408      }
+409    });
+410  }
+411
+412
+413  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+414
+415  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+416  @Override @Test
+417  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+418    notVerified(); // cannot be meaningfully tested, or can it?
+419  }
+420
+421  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+422  @Override @Test
+423  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+424    subscriberTest(new TestStageTestRun() {
+425      @Override
+426      public void run(WhiteboxTestStage stage) throws InterruptedException {
+427        stage.puppet().triggerRequest(2);
+428        stage.probe.expectNext(stage.signalNext());
+429        stage.probe.expectNext(stage.signalNext());
+430
+431        stage.probe.expectNone();
+432        stage.puppet().triggerRequest(3);
+433
+434        stage.verifyNoAsyncErrors();
+435      }
+436    });
+437  }
+438
+439  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+440  @Override @Test
+441  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+442    notVerified(); // cannot be meaningfully tested, or can it?
+443  }
+444
+445  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+446  @Override @Test
+447  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+448    notVerified(); // cannot be meaningfully tested, or can it?
+449  }
+450
+451  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+452  @Override @Test
+453  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+454    notVerified(); // cannot be meaningfully tested, or can it?
+455  }
+456
+457  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+458  @Override @Test
+459  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+460    notVerified(); // cannot be meaningfully tested, or can it?
+461  }
+462
+463  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+464  @Override @Test
+465  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+466    notVerified(); // cannot be meaningfully tested, or can it?
+467  }
+468
+469  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+470
+471  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+472
+473  abstract class TestStageTestRun {
+474    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+475  }
+476
+477  /**
+478   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+479   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+480   *
+481   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+482   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+483   */
+484  public void subscriberTest(TestStageTestRun body) throws Throwable {
+485    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+486    body.run(stage);
+487  }
+488
+489  /**
+490   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+491   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+492   *
+493   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+494   */
+495  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+496    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+497    body.run(stage);
+498  }
+499
+500  /**
+501   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+502   */
+503  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+504    try {
+505      subscriberTestWithoutSetup(body);
+506    } catch (Exception ex) {
+507      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+508    }
+509  }
+510
+511  public class WhiteboxTestStage extends ManualPublisher<T> {
+512    public Publisher<T> pub;
+513    public ManualSubscriber<T> tees; // gives us access to a stream T values
+514    public WhiteboxSubscriberProbe<T> probe;
+515
+516    public T lastT = null;
+517
+518    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+519      this(env, true);
+520    }
+521
+522    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+523      super(env);
+524      if (runDefaultInit) {
+525        pub = this.createHelperPublisher(Long.MAX_VALUE);
+526        tees = env.newManualSubscriber(pub);
+527        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+528        subscribe(createSubscriber(probe));
+529        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+530      }
+531    }
+532
+533    public Subscriber<? super T> sub() {
+534      return subscriber.value();
+535    }
+536
+537    public SubscriberPuppet puppet() {
+538      return probe.puppet();
+539    }
+540
+541    public WhiteboxSubscriberProbe<T> probe() {
+542      return probe;
+543    }
+544
+545    public Publisher<T> createHelperPublisher(long elements) {
+546      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+547    }
+548
+549    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+550      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+551    }
+552
+553    public T signalNext() throws InterruptedException {
+554      return signalNext(nextT());
+555    }
+556
+557    private T signalNext(T element) throws InterruptedException {
+558      sendNext(element);
+559      return element;
+560    }
+561
+562    public T nextT() throws InterruptedException {
+563      lastT = tees.requestNextElement();
+564      return lastT;
+565    }
+566
+567    public void verifyNoAsyncErrors() {
+568      env.verifyNoAsyncErrors();
+569    }
+570  }
+571
+572  /**
+573   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+574   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+575   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+576   */
+577  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+578
+579    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+580      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+581    }
+582
+583    @Override
+584    public void onSubscribe(Subscription s) {
+585      sub().onSubscribe(s);
+586    }
+587
+588    @Override
+589    public void onNext(T t) {
+590      registerOnNext(t);
+591      sub().onNext(t);
+592    }
+593
+594    @Override
+595    public void onError(Throwable cause) {
+596      registerOnError(cause);
+597      sub().onError(cause);
+598    }
+599
+600    @Override
+601    public void onComplete() {
+602      registerOnComplete();
+603      sub().onComplete();
+604    }
+605  }
+606
+607  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+608    protected final TestEnvironment env;
+609    protected final Promise<Subscriber<? super T>> subscriber;
+610
+611    protected final Receptacle<T> elements;
+612    protected final Promise<Throwable> error;
+613
+614    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+615      this.env = env;
+616      this.subscriber = subscriber;
+617      elements = new Receptacle<T>(env);
+618      error = new Promise<Throwable>(env);
+619    }
+620
+621    @Override
+622    public void registerOnNext(T element) {
+623      elements.add(element);
+624    }
+625
+626    @Override
+627    public void registerOnComplete() {
+628      try {
+629        elements.complete();
+630      } catch (IllegalStateException ex) {
+631        // "Queue full", onComplete was already called
+632        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+633      }
+634    }
+635
+636    @Override
+637    public void registerOnError(Throwable cause) {
+638      try {
+639        error.complete(cause);
+640      } catch (IllegalStateException ex) {
+641        // "Queue full", onError was already called
+642        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+643      }
+644    }
+645
+646    public T expectNext() throws InterruptedException {
+647      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+648    }
+649
+650    public void expectNext(T expected) throws InterruptedException {
+651      expectNext(expected, env.defaultTimeoutMillis());
+652    }
+653
+654    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+655      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+656      if (!received.equals(expected)) {
+657        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+658      }
+659    }
+660
+661    public Subscriber<? super T> sub() {
+662      return subscriber.value();
+663    }
+664
+665    public void expectCompletion() throws InterruptedException {
+666      expectCompletion(env.defaultTimeoutMillis());
+667    }
+668
+669    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+670      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+671    }
+672
+673    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+674      elements.expectCompletion(timeoutMillis, msg);
+675    }
+676
+677    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+678    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+679      final E err = expectError(expected);
+680      String message = err.getMessage();
+681      assertTrue(message.contains(requiredMessagePart),
+682        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+683    }
+684
+685    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+686      return expectError(expected, env.defaultTimeoutMillis());
+687    }
+688
+689    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+690    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+691      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+692      if (error.value() == null) {
+693        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+694      } else if (expected.isInstance(error.value())) {
+695        return (E) error.value();
+696      } else {
+697        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+698      }
+699    }
+700
+701    public void expectError(Throwable expected) throws InterruptedException {
+702      expectError(expected, env.defaultTimeoutMillis());
+703    }
+704
+705    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+706    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+707      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+708      if (error.value() != expected) {
+709        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+710      }
+711    }
+712
+713    public void expectNone() throws InterruptedException {
+714      expectNone(env.defaultTimeoutMillis());
+715    }
+716
+717    public void expectNone(long withinMillis) throws InterruptedException {
+718      elements.expectNone(withinMillis, "Expected nothing");
+719    }
+720
+721  }
+722
+723  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+724    protected Promise<SubscriberPuppet> puppet;
+725
+726    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+727      super(env, subscriber);
+728      puppet = new Promise<SubscriberPuppet>(env);
+729    }
+730
+731    private SubscriberPuppet puppet() {
+732      return puppet.value();
+733    }
+734
+735    @Override
+736    public void registerOnSubscribe(SubscriberPuppet p) {
+737      if (!puppet.isCompleted()) {
+738        puppet.complete(p);
+739      } 
+740    }
+741
+742  }
+743
+744  public interface SubscriberPuppeteer {
+745
+746    /**
+747     * Must be called by the test subscriber when it has successfully registered a subscription
+748     * inside the `onSubscribe` method.
+749     */
+750    void registerOnSubscribe(SubscriberPuppet puppet);
+751  }
+752
+753  public interface SubscriberProbe<T> {
+754
+755    /**
+756     * Must be called by the test subscriber when it has received an`onNext` event.
+757     */
+758    void registerOnNext(T element);
+759
+760    /**
+761     * Must be called by the test subscriber when it has received an `onComplete` event.
+762     */
+763    void registerOnComplete();
+764
+765    /**
+766     * Must be called by the test subscriber when it has received an `onError` event.
+767     */
+768    void registerOnError(Throwable cause);
+769
+770  }
+771
+772  public interface SubscriberPuppet {
+773    void triggerRequest(long elements);
+774
+775    void signalCancel();
+776  }
+777
+778  public void notVerified() {
+779    throw new SkipException("Not verified using this TCK.");
+780  }
+781
+782  public void notVerified(String msg) {
+783    throw new SkipException(msg);
+784  }
+785}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.BlackholeSubscriberWithSubscriptionSupport.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Latch.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Latch.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Latch.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualPublisher.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriber.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.ManualSubscriberWithSubscriptionSupport.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Promise.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Promise.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Promise.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Receptacle.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Receptacle.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.Receptacle.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.TestSubscriber.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.html new file mode 100644 index 0000000..f034ba2 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/TestEnvironment.html @@ -0,0 +1,1031 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.Subscriber;
+005import org.reactivestreams.Subscription;
+006import org.reactivestreams.tck.support.SubscriberBufferOverflowException;
+007import org.reactivestreams.tck.support.Optional;
+008
+009import java.util.LinkedList;
+010import java.util.List;
+011import java.util.concurrent.ArrayBlockingQueue;
+012import java.util.concurrent.CopyOnWriteArrayList;
+013import java.util.concurrent.CountDownLatch;
+014import java.util.concurrent.TimeUnit;
+015
+016import static org.testng.Assert.assertTrue;
+017import static org.testng.Assert.fail;
+018
+019public class TestEnvironment {
+020  public static final int TEST_BUFFER_SIZE = 16;
+021
+022  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+023  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+024
+025  private final long defaultTimeoutMillis;
+026  private final boolean printlnDebug;
+027
+028  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+029
+030  /**
+031   * Tests must specify the timeout for expected outcome of asynchronous
+032   * interactions. Longer timeout does not invalidate the correctness of
+033   * the implementation, but can in some cases result in longer time to
+034   * run the tests.
+035   *
+036   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+037   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+038   *                             often helpful to pinpoint simple race conditions etc.
+039   */
+040  public TestEnvironment(long defaultTimeoutMillis, boolean printlnDebug) {
+041    this.defaultTimeoutMillis = defaultTimeoutMillis;
+042    this.printlnDebug = printlnDebug;
+043  }
+044
+045  /**
+046   * Tests must specify the timeout for expected outcome of asynchronous
+047   * interactions. Longer timeout does not invalidate the correctness of
+048   * the implementation, but can in some cases result in longer time to
+049   * run the tests.
+050   *
+051   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+052   */
+053  public TestEnvironment(long defaultTimeoutMillis) {
+054    this(defaultTimeoutMillis, false);
+055  }
+056
+057  /**
+058   * Tests must specify the timeout for expected outcome of asynchronous
+059   * interactions. Longer timeout does not invalidate the correctness of
+060   * the implementation, but can in some cases result in longer time to
+061   * run the tests.
+062   *
+063   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+064   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+065   *
+066   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+067   *                     often helpful to pinpoint simple race conditions etc.
+068   */
+069  public TestEnvironment(boolean printlnDebug) {
+070    this(envDefaultTimeoutMillis(), printlnDebug);
+071  }
+072
+073  /**
+074   * Tests must specify the timeout for expected outcome of asynchronous
+075   * interactions. Longer timeout does not invalidate the correctness of
+076   * the implementation, but can in some cases result in longer time to
+077   * run the tests.
+078   *
+079   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+080   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+081   */
+082  public TestEnvironment() {
+083    this(envDefaultTimeoutMillis());
+084  }
+085
+086  public long defaultTimeoutMillis() {
+087    return defaultTimeoutMillis;
+088  }
+089
+090  /**
+091   * Tries to parse the env variable {@code DEFAULT_TIMEOUT_MILLIS} as long and returns the value if present OR its default value.
+092   *
+093   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+094   */
+095  public static long envDefaultTimeoutMillis() {
+096    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+097    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+098    else try {
+099      return Long.parseLong(envMillis);
+100    } catch(NumberFormatException ex) {
+101      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+102    }
+103  }
+104
+105  /**
+106   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+107   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+108   *
+109   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+110   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+111   * from the environment using {@code env.dropAsyncError()}.
+112   *
+113   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+114   */
+115  public void flop(String msg) {
+116    try {
+117      fail(msg);
+118    } catch (Throwable t) {
+119      asyncErrors.add(t);
+120    }
+121  }
+122
+123  /**
+124   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+125   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+126   *
+127   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+128   *
+129   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+130   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+131   * from the environment using {@code env.dropAsyncError()}.
+132   *
+133   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+134   */
+135  public void flop(Throwable thr, String msg) {
+136    try {
+137      fail(msg, thr);
+138    } catch (Throwable t) {
+139      asyncErrors.add(thr);
+140    }
+141  }
+142  
+143  /**
+144   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+145   * This method does *NOT* fail the test - it's up to inspections of the error to fail the test if required.
+146   *
+147   * This overload keeps the passed in throwable as the asyncError, instead of creating an AssertionError for this.
+148   *
+149   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+150   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+151   * from the environment using {@code env.dropAsyncError()}.
+152   *
+153   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+154   */
+155  public void flop(Throwable thr) {
+156    try {
+157      fail(thr.getMessage(), thr);
+158    } catch (Throwable t) {
+159      asyncErrors.add(thr);
+160    }
+161  }
+162
+163  /**
+164   * To flop means to "fail asynchronously", either by onErroring or by failing some TCK check triggered asynchronously.
+165   *
+166   * This method DOES fail the test right away (it tries to, by throwing an AssertionException),
+167   * in such it is different from {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+168   *
+169   * Use {@code env.verifyNoAsyncErrorsNoDelay()} at the end of your TCK tests to verify there no flops called during it's execution.
+170   * To check investigate asyncErrors more closely you can use {@code expectError} methods or collect the error directly
+171   * from the environment using {@code env.dropAsyncError()}.
+172   *
+173   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+174   */
+175  public <T> T flopAndFail(String msg) {
+176    try {
+177      fail(msg);
+178    } catch (Throwable t) {
+179      asyncErrors.add(t);
+180      fail(msg, t);
+181    }
+182    return null; // unreachable, the previous block will always exit by throwing
+183  }
+184
+185
+186
+187  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+188    subscribe(pub, sub, defaultTimeoutMillis);
+189  }
+190
+191  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+192    pub.subscribe(sub);
+193    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+194    verifyNoAsyncErrorsNoDelay();
+195  }
+196
+197  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+198    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+199    subscribe(pub, sub, defaultTimeoutMillis());
+200    return sub;
+201  }
+202
+203  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+204    return newManualSubscriber(pub, defaultTimeoutMillis());
+205  }
+206
+207  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+208    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+209    subscribe(pub, sub, timeoutMillis);
+210    return sub;
+211  }
+212
+213  public void clearAsyncErrors() {
+214    asyncErrors.clear();
+215  }
+216
+217  public Throwable dropAsyncError() {
+218    try {
+219      return asyncErrors.remove(0);
+220    } catch (IndexOutOfBoundsException ex) {
+221      return null;
+222    }
+223  }
+224
+225  /**
+226   * Waits for {@link TestEnvironment#defaultTimeoutMillis()} and then verifies that no asynchronous errors
+227   * were signalled pior to, or during that time (by calling {@code flop()}).
+228   */
+229  public void verifyNoAsyncErrors() {
+230    verifyNoAsyncErrors(defaultTimeoutMillis());
+231  }
+232
+233  /**
+234   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+235   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+236   * <p></p>
+237   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#flop(String)},
+238   * and if no errors encountered wait for another default timeout as the errors may yet be signalled.
+239   * The initial check is performed in order to fail-fast in case of an already failed test.
+240   */
+241  public void verifyNoAsyncErrors(long delay) {
+242    try {
+243      verifyNoAsyncErrorsNoDelay();
+244
+245      Thread.sleep(delay);
+246      verifyNoAsyncErrorsNoDelay();
+247    } catch (InterruptedException e) {
+248      throw new RuntimeException(e);
+249    }
+250  }
+251
+252  /**
+253   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+254   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+255   * for example in tight loops etc.
+256   */
+257  public void verifyNoAsyncErrorsNoDelay() {
+258    for (Throwable e : asyncErrors) {
+259      if (e instanceof AssertionError) {
+260        throw (AssertionError) e;
+261      } else {
+262        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+263      }
+264    }
+265  }
+266
+267  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+268  public void debug(String msg) {
+269    if (printlnDebug)
+270      System.out.printf("[TCK-DEBUG] %s%n", msg);
+271  }
+272
+273  /**
+274   * Looks for given {@code method} method in stack trace.
+275   * Can be used to answer questions like "was this method called from onComplete?".
+276   *
+277   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+278   */
+279  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+280    final Throwable thr = new Throwable(); // gets the stacktrace
+281
+282    for (StackTraceElement stackElement : thr.getStackTrace()) {
+283      if (stackElement.getMethodName().equals(method)) {
+284        return Optional.of(stackElement);
+285      }
+286    }
+287    return Optional.empty();
+288  }
+289
+290  // ---- classes ----
+291
+292  /**
+293   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+294   */
+295  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+296    Receptacle<T> received;
+297
+298    public ManualSubscriber(TestEnvironment env) {
+299      super(env);
+300      received = new Receptacle<T>(this.env);
+301    }
+302
+303    @Override
+304    public void onNext(T element) {
+305      try {
+306        received.add(element);
+307      } catch (IllegalStateException ex) {
+308          // error message refinement
+309          throw new SubscriberBufferOverflowException(
+310            String.format("Received more than bufferSize (%d) onNext signals. " +
+311                            "The Publisher probably emited more signals than expected!",
+312                          received.QUEUE_SIZE), ex);
+313      }
+314    }
+315
+316    @Override
+317    public void onComplete() {
+318      received.complete();
+319    }
+320
+321    public void request(long elements) {
+322      subscription.value().request(elements);
+323    }
+324
+325    public T requestNextElement() throws InterruptedException {
+326      return requestNextElement(env.defaultTimeoutMillis());
+327    }
+328
+329    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+330      return requestNextElement(timeoutMillis, "Did not receive expected element");
+331    }
+332
+333    public T requestNextElement(String errorMsg) throws InterruptedException {
+334      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+335    }
+336
+337    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+338      request(1);
+339      return nextElement(timeoutMillis, errorMsg);
+340    }
+341
+342    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+343      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+344    }
+345
+346    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+347      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+348    }
+349
+350    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+351      request(1);
+352      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+353    }
+354
+355    public void requestEndOfStream() throws InterruptedException {
+356      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+357    }
+358
+359    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+360      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+361    }
+362
+363    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+364      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+365    }
+366
+367    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+368      request(1);
+369      expectCompletion(timeoutMillis, errorMsg);
+370    }
+371
+372    public List<T> requestNextElements(long elements) throws InterruptedException {
+373      request(elements);
+374      return nextElements(elements, env.defaultTimeoutMillis());
+375    }
+376
+377    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+378      request(elements);
+379      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+380    }
+381
+382    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+383      request(elements);
+384      return nextElements(elements, timeoutMillis, errorMsg);
+385    }
+386
+387    public T nextElement() throws InterruptedException {
+388      return nextElement(env.defaultTimeoutMillis());
+389    }
+390
+391    public T nextElement(long timeoutMillis) throws InterruptedException {
+392      return nextElement(timeoutMillis, "Did not receive expected element");
+393    }
+394
+395    public T nextElement(String errorMsg) throws InterruptedException {
+396      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+397    }
+398
+399    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+400      return received.next(timeoutMillis, errorMsg);
+401    }
+402
+403    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+404      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+405    }
+406
+407    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+408      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+409    }
+410
+411    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+412      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+413    }
+414
+415    public List<T> nextElements(long elements) throws InterruptedException {
+416      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+417    }
+418
+419    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+420      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+421    }
+422
+423    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+424      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+425    }
+426
+427    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+428      return received.nextN(elements, timeoutMillis, errorMsg);
+429    }
+430
+431    public void expectNext(T expected) throws InterruptedException {
+432      expectNext(expected, env.defaultTimeoutMillis());
+433    }
+434
+435    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+436      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+437      if (!received.equals(expected)) {
+438        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+439      }
+440    }
+441
+442    public void expectCompletion() throws InterruptedException {
+443      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+444    }
+445
+446    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+447      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+448    }
+449
+450    public void expectCompletion(String errorMsg) throws InterruptedException {
+451      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+452    }
+453
+454    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+455      received.expectCompletion(timeoutMillis, errorMsg);
+456    }
+457
+458    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+459      expectErrorWithMessage(expected, requiredMessagePart, env.defaultTimeoutMillis());
+460    }
+461
+462    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+463    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+464      final E err = expectError(expected, timeoutMillis);
+465      final String message = err.getMessage();
+466      assertTrue(message.contains(requiredMessagePart),
+467                 String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+468                               err.getClass(), requiredMessagePart, err.getMessage()));
+469    }
+470
+471    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+472      return expectError(expected, env.defaultTimeoutMillis());
+473    }
+474
+475    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+476      return expectError(expected, timeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+477    }
+478
+479    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+480      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+481    }
+482
+483    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+484      return received.expectError(expected, timeoutMillis, errorMsg);
+485    }
+486
+487    public void expectNone() throws InterruptedException {
+488      expectNone(env.defaultTimeoutMillis());
+489    }
+490
+491    public void expectNone(String errMsgPrefix) throws InterruptedException {
+492      expectNone(env.defaultTimeoutMillis(), errMsgPrefix);
+493    }
+494
+495    public void expectNone(long withinMillis) throws InterruptedException {
+496      expectNone(withinMillis, "Did not expect an element but got element");
+497    }
+498
+499    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+500      received.expectNone(withinMillis, errMsgPrefix);
+501    }
+502
+503  }
+504
+505  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+506
+507    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+508      super(env);
+509    }
+510
+511    @Override
+512    public void onNext(T element) {
+513      env.debug(String.format("%s::onNext(%s)", this, element));
+514      if (subscription.isCompleted()) {
+515        super.onNext(element);
+516      } else {
+517        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+518      }
+519    }
+520
+521    @Override
+522    public void onComplete() {
+523      env.debug(this + "::onComplete()");
+524      if (subscription.isCompleted()) {
+525        super.onComplete();
+526      } else {
+527        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+528      }
+529    }
+530
+531    @Override
+532    public void onSubscribe(Subscription s) {
+533      env.debug(String.format("%s::onSubscribe(%s)", this, s));
+534      if (!subscription.isCompleted()) {
+535        subscription.complete(s);
+536      } else {
+537        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+538      }
+539    }
+540
+541    @Override
+542    public void onError(Throwable cause) {
+543      env.debug(String.format("%s::onError(%s)", this, cause));
+544      if (subscription.isCompleted()) {
+545        super.onError(cause);
+546      } else {
+547        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+548      }
+549    }
+550  }
+551
+552  /**
+553   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+554   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+555   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+556   */
+557  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+558    extends ManualSubscriberWithSubscriptionSupport<T> {
+559
+560    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+561      super(env);
+562    }
+563
+564    @Override
+565    public void onNext(T element) {
+566      env.debug(String.format("%s::onNext(%s)", this, element));
+567      if (!subscription.isCompleted()) {
+568        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+569      }
+570    }
+571
+572    @Override
+573    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+574      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+575    }
+576
+577    @Override
+578    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+579      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+580    }
+581  }
+582
+583  public static class TestSubscriber<T> implements Subscriber<T> {
+584    final Promise<Subscription> subscription;
+585
+586    protected final TestEnvironment env;
+587
+588    public TestSubscriber(TestEnvironment env) {
+589      this.env = env;
+590      subscription = new Promise<Subscription>(env);
+591    }
+592
+593    @Override
+594    public void onError(Throwable cause) {
+595      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+596    }
+597
+598    @Override
+599    public void onComplete() {
+600      env.flop("Unexpected Subscriber::onComplete()");
+601    }
+602
+603    @Override
+604    public void onNext(T element) {
+605      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+606    }
+607
+608    @Override
+609    public void onSubscribe(Subscription subscription) {
+610      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+611    }
+612
+613    public void cancel() {
+614      if (subscription.isCompleted()) {
+615        subscription.value().cancel();
+616      } else {
+617        env.flop("Cannot cancel a subscription before having received it");
+618      }
+619    }
+620  }
+621
+622  public static class ManualPublisher<T> implements Publisher<T> {
+623    protected final TestEnvironment env;
+624
+625    protected long pendingDemand = 0L;
+626    protected Promise<Subscriber<? super T>> subscriber;
+627
+628    protected final Receptacle<Long> requests;
+629
+630    protected final Latch cancelled;
+631
+632    public ManualPublisher(TestEnvironment env) {
+633      this.env = env;
+634      requests = new Receptacle<Long>(env);
+635      cancelled = new Latch(env);
+636      subscriber = new Promise<Subscriber<? super T>>(this.env);
+637    }
+638
+639    @Override
+640    public void subscribe(Subscriber<? super T> s) {
+641      if (!subscriber.isCompleted()) {
+642        subscriber.completeImmediatly(s);
+643
+644        Subscription subs = new Subscription() {
+645          @Override
+646          public void request(long elements) {
+647            requests.add(elements);
+648          }
+649
+650          @Override
+651          public void cancel() {
+652            cancelled.close();
+653          }
+654        };
+655        s.onSubscribe(subs);
+656
+657      } else {
+658        env.flop("TestPublisher doesn't support more than one Subscriber");
+659      }
+660    }
+661
+662    public void sendNext(T element) {
+663      if (subscriber.isCompleted()) {
+664        subscriber.value().onNext(element);
+665      } else {
+666        env.flop("Cannot sendNext before having a Subscriber");
+667      }
+668    }
+669
+670    public void sendCompletion() {
+671      if (subscriber.isCompleted()) {
+672        subscriber.value().onComplete();
+673      } else {
+674        env.flop("Cannot sendCompletion before having a Subscriber");
+675      }
+676    }
+677
+678    public void sendError(Throwable cause) {
+679      if (subscriber.isCompleted()) {
+680        subscriber.value().onError(cause);
+681      } else {
+682        env.flop("Cannot sendError before having a Subscriber");
+683      }
+684    }
+685
+686    public long expectRequest() throws InterruptedException {
+687      return expectRequest(env.defaultTimeoutMillis());
+688    }
+689
+690    public long expectRequest(long timeoutMillis) throws InterruptedException {
+691      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+692      if (requested <= 0) {
+693        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+694      } else {
+695        pendingDemand += requested;
+696        return requested;
+697      }
+698    }
+699
+700    public void expectExactRequest(long expected) throws InterruptedException {
+701      expectExactRequest(expected, env.defaultTimeoutMillis());
+702    }
+703
+704    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+705      long requested = expectRequest(timeoutMillis);
+706      if (requested != expected) {
+707        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+708      }
+709      pendingDemand += requested;
+710    }
+711
+712    public void expectNoRequest() throws InterruptedException {
+713      expectNoRequest(env.defaultTimeoutMillis());
+714    }
+715
+716    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+717      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+718    }
+719
+720    public void expectCancelling() throws InterruptedException {
+721      expectCancelling(env.defaultTimeoutMillis());
+722    }
+723
+724    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+725      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+726    }
+727  }
+728
+729  /**
+730   * Like a CountDownLatch, but resettable and with some convenience methods
+731   */
+732  public static class Latch {
+733    private final TestEnvironment env;
+734    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+735
+736    public Latch(TestEnvironment env) {
+737      this.env = env;
+738    }
+739
+740    public void reOpen() {
+741      countDownLatch = new CountDownLatch(1);
+742    }
+743
+744    public boolean isClosed() {
+745      return countDownLatch.getCount() == 0;
+746    }
+747
+748    public void close() {
+749      countDownLatch.countDown();
+750    }
+751
+752    public void assertClosed(String openErrorMsg) {
+753      if (!isClosed()) {
+754        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+755      }
+756    }
+757
+758    public void assertOpen(String closedErrorMsg) {
+759      if (isClosed()) {
+760        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+761      }
+762    }
+763
+764    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+765      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+766    }
+767
+768    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+769      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+770      if (countDownLatch.getCount() > 0) {
+771        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+772      }
+773    }
+774
+775    static final class ExpectedOpenLatchException extends RuntimeException {
+776      public ExpectedOpenLatchException(String message) {
+777        super(message);
+778      }
+779    }
+780
+781    static final class ExpectedClosedLatchException extends RuntimeException {
+782      public ExpectedClosedLatchException(String message) {
+783        super(message);
+784      }
+785    }
+786
+787  }
+788
+789  // simple promise for *one* value, which cannot be reset
+790  public static class Promise<T> {
+791    private final TestEnvironment env;
+792
+793    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+794      Promise<T> promise = new Promise<T>(env);
+795      promise.completeImmediatly(value);
+796      return promise;
+797    }
+798
+799    public Promise(TestEnvironment env) {
+800      this.env = env;
+801    }
+802
+803    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+804    private volatile T _value = null;
+805
+806    public T value() {
+807      if (isCompleted()) {
+808        return _value;
+809      } else {
+810        env.flop("Cannot access promise value before completion");
+811        return null;
+812      }
+813    }
+814
+815    public boolean isCompleted() {
+816      return _value != null;
+817    }
+818
+819    /**
+820     * Allows using expectCompletion to await for completion of the value and complete it _then_
+821     */
+822    public void complete(T value) {
+823      abq.add(value);
+824    }
+825
+826    /**
+827     * Completes the promise right away, it is not possible to expectCompletion on a Promise completed this way
+828     */
+829    public void completeImmediatly(T value) {
+830      complete(value); // complete!
+831      _value = value;  // immediatly!
+832    }
+833
+834    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+835      if (!isCompleted()) {
+836        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+837
+838        if (val == null) {
+839          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+840        } else {
+841          _value = val;
+842        }
+843      }
+844    }
+845  }
+846
+847  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+848  public static class Receptacle<T> {
+849    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+850    private final TestEnvironment env;
+851
+852    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+853
+854    private final Latch completedLatch;
+855
+856    Receptacle(TestEnvironment env) {
+857      this.env = env;
+858      this.completedLatch = new Latch(env);
+859    }
+860
+861    public void add(T value) {
+862      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+863
+864      abq.add(Optional.of(value));
+865    }
+866
+867    public void complete() {
+868      completedLatch.assertOpen("Unexpected additional complete signal received!");
+869      completedLatch.close();
+870
+871      abq.add(Optional.<T>empty());
+872    }
+873
+874    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+875      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+876
+877      if (value == null) {
+878        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+879      } else if (value.isDefined()) {
+880        return value.get();
+881      } else {
+882        return env.flopAndFail("Expected element but got end-of-stream");
+883      }
+884    }
+885
+886    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+887      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+888
+889      if (value == null) {
+890        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+891        return Optional.empty();
+892      }
+893
+894      return value;
+895    }
+896
+897    /**
+898     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+899     */
+900    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+901      List<T> result = new LinkedList<T>();
+902      long remaining = elements;
+903      long deadline = System.currentTimeMillis() + timeoutMillis;
+904      while (remaining > 0) {
+905        long remainingMillis = deadline - System.currentTimeMillis();
+906
+907        result.add(next(remainingMillis, errorMsg));
+908        remaining--;
+909      }
+910
+911      return result;
+912    }
+913
+914
+915    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+916      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+917
+918      if (value == null) {
+919        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+920      } else if (value.isDefined()) {
+921        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+922      } // else, ok
+923    }
+924
+925    @SuppressWarnings("unchecked")
+926    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+927      Thread.sleep(timeoutMillis);
+928
+929      if (env.asyncErrors.isEmpty()) {
+930        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+931      } else {
+932        // ok, there was an expected error
+933        Throwable thrown = env.asyncErrors.remove(0);
+934
+935        if (clazz.isInstance(thrown)) {
+936          return (E) thrown;
+937        } else {
+938
+939          return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+940                                               errorMsg, timeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+941        }
+942      }
+943    }
+944
+945    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+946      Thread.sleep(withinMillis);
+947      Optional<T> value = abq.poll();
+948
+949      if (value == null) {
+950        // ok
+951      } else if (value.isDefined()) {
+952        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+953      } else {
+954        env.flop("Expected no element but got end-of-stream");
+955      }
+956    }
+957  }
+958}
+959
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/WithHelperPublisher.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/WithHelperPublisher.html new file mode 100644 index 0000000..5dabdae --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/WithHelperPublisher.html @@ -0,0 +1,141 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck;
+002
+003import org.reactivestreams.Publisher;
+004import org.reactivestreams.tck.support.Function;
+005import org.reactivestreams.tck.support.HelperPublisher;
+006import org.reactivestreams.tck.support.InfiniteHelperPublisher;
+007
+008import java.util.concurrent.ExecutorService;
+009
+010/**
+011 * Type which is able to create elements based on a seed {@code id} value.
+012 * <p>
+013 * Simplest implementations will simply return the incoming id as the element.
+014 *
+015 * @param <T> type of element to be delivered to the Subscriber
+016 */
+017public abstract class WithHelperPublisher<T> {
+018
+019  /** ExecutorService to be used by the provided helper {@link org.reactivestreams.Publisher} */
+020  public abstract ExecutorService publisherExecutorService();
+021
+022  /**
+023   * Implement this method to match your expected element type.
+024   * In case of implementing a simple Subscriber which is able to consume any kind of element simply return the
+025   * incoming {@code element} element.
+026   * <p>
+027   * Sometimes the Subscriber may be limited in what type of element it is able to consume, this you may have to implement
+028   * this method such that the emitted element matches the Subscribers requirements. Simplest implementations would be
+029   * to simply pass in the {@code element} as payload of your custom element, such as appending it to a String or other identifier.
+030   * <p>
+031   * <b>Warning:</b> This method may be called concurrently by the helper publisher, thus it should be implemented in a
+032   * thread-safe manner.
+033   *
+034   * @return element of the matching type {@code T} that will be delivered to the tested Subscriber
+035   */
+036  public abstract T createElement(int element);
+037
+038  /**
+039   * Helper method required for creating the Publisher to which the tested Subscriber will be subscribed and tested against.
+040   * <p>
+041   * By default an <b>asynchronously signalling Publisher</b> is provided, which will use {@link #createElement(int)}
+042   * to generate elements type your Subscriber is able to consume.
+043   * <p>
+044   * Sometimes you may want to implement your own custom custom helper Publisher - to validate behaviour of a Subscriber
+045   * when facing a synchronous Publisher for example. If you do, it MUST emit the exact number of elements asked for
+046   * (via the {@code elements} parameter) and MUST also must treat the following numbers of elements in these specific ways:
+047   * <ul>
+048   *   <li>
+049   *     If {@code elements} is {@code Long.MAX_VALUE} the produced stream must be infinite.
+050   *   </li>
+051   *   <li>
+052   *     If {@code elements} is {@code 0} the {@code Publisher} should signal {@code onComplete} immediatly.
+053   *     In other words, it should represent a "completed stream".
+054   *   </li>
+055   * </ul>
+056   */
+057  @SuppressWarnings("unchecked")
+058  public Publisher<T> createHelperPublisher(long elements) {
+059    final Function<Integer, T> mkElement = new Function<Integer, T>() {
+060      @Override public T apply(Integer id) throws Throwable {
+061        return createElement(id);
+062      }
+063    };
+064
+065    if (elements > Integer.MAX_VALUE) return new InfiniteHelperPublisher(mkElement, publisherExecutorService());
+066    else return new HelperPublisher(0, (int) elements, mkElement, publisherExecutorService());
+067  }
+068
+069}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Function.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Function.html new file mode 100644 index 0000000..0227554 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Function.html @@ -0,0 +1,77 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003public interface Function<In, Out> {
+004  public Out apply(In in) throws Throwable;
+005}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/HelperPublisher.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/HelperPublisher.html new file mode 100644 index 0000000..fe5577e --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/HelperPublisher.html @@ -0,0 +1,105 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003import java.util.Collections;
+004import java.util.Iterator;
+005import java.util.concurrent.Executor;
+006import org.reactivestreams.Subscription;
+007import org.reactivestreams.Subscriber;
+008import org.reactivestreams.Publisher;
+009import org.reactivestreams.example.unicast.AsyncIterablePublisher;
+010
+011public class HelperPublisher<T> extends AsyncIterablePublisher<T> {
+012  
+013    public HelperPublisher(final int from, final int to, final Function<Integer, T> create, final Executor executor) {
+014        super(new Iterable<T>() {
+015          { if(from > to) throw new IllegalArgumentException("from must be equal or greater than to!"); }
+016          @Override public Iterator<T> iterator() {
+017            return new Iterator<T>() {
+018              private int at = from;
+019              @Override public boolean hasNext() { return at < to; }
+020              @Override public T next() {
+021                if (!hasNext()) return Collections.<T>emptyList().iterator().next();
+022                else try {
+023                  return create.apply(at++);
+024                } catch (Throwable t) {
+025                  throw new IllegalStateException(String.format("Failed to create element for id %d!", at - 1), t);
+026                }
+027              }
+028              @Override public void remove() { throw new UnsupportedOperationException(); }
+029            };
+030          }
+031        }, executor);
+032    }
+033}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/InfiniteHelperPublisher.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/InfiniteHelperPublisher.html new file mode 100644 index 0000000..7ae7d04 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/InfiniteHelperPublisher.html @@ -0,0 +1,102 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003import org.reactivestreams.example.unicast.AsyncIterablePublisher;
+004
+005import java.util.Iterator;
+006import java.util.concurrent.Executor;
+007
+008public class InfiniteHelperPublisher<T> extends AsyncIterablePublisher<T> {
+009
+010    public InfiniteHelperPublisher(final Function<Integer, T> create, final Executor executor) {
+011        super(new Iterable<T>() {
+012          @Override public Iterator<T> iterator() {
+013            return new Iterator<T>() {
+014              private int at = 0;
+015
+016              @Override public boolean hasNext() { return true; }
+017              @Override public T next() {
+018                try {
+019                  return create.apply(at++); // Wraps around on overflow
+020                } catch (Throwable t) {
+021                  throw new IllegalStateException(
+022                    String.format("Failed to create element in %s for id %s!", getClass().getSimpleName(), at - 1), t);
+023                }
+024              }
+025              @Override public void remove() { throw new UnsupportedOperationException(); }
+026            };
+027          }
+028        }, executor);
+029    }
+030}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/NonFatal.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/NonFatal.html new file mode 100644 index 0000000..fba742c --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/NonFatal.html @@ -0,0 +1,104 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003
+004/**
+005 * Copy of scala.control.util.NonFatal in order to not depend on scala-library
+006 */
+007public class NonFatal {
+008  private NonFatal() {
+009    // no instances, please.
+010  }
+011
+012  /**
+013   * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
+014   *
+015   * @param t throwable to be matched for fatal-ness
+016   * @return true if is a non-fatal throwable, false otherwise
+017   */
+018  public static boolean isNonFatal(Throwable t) {
+019    if (t instanceof StackOverflowError) {
+020      // StackOverflowError ok even though it is a VirtualMachineError
+021      return true;
+022    } else if (t instanceof VirtualMachineError ||
+023        t instanceof ThreadDeath ||
+024        t instanceof InterruptedException ||
+025        t instanceof LinkageError) {
+026      // VirtualMachineError includes OutOfMemoryError and other fatal errors
+027      return false;
+028    } else {
+029      return true;
+030    }
+031  }
+032}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.Some.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.Some.html new file mode 100644 index 0000000..e53bc7d --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.Some.html @@ -0,0 +1,141 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003import java.util.NoSuchElementException;
+004
+005// simplest possible version of Scala's Option type
+006public abstract class Optional<T> {
+007
+008  private static final Optional<Object> NONE = new Optional<Object>() {
+009    @Override
+010    public Object get() {
+011      throw new NoSuchElementException(".get call on None!");
+012    }
+013
+014    @Override
+015    public boolean isEmpty() {
+016      return true;
+017    }
+018  };
+019
+020  private Optional() {
+021  }
+022
+023  @SuppressWarnings("unchecked")
+024  public static <T> Optional<T> empty() {
+025    return (Optional<T>) NONE;
+026  }
+027
+028  @SuppressWarnings("unchecked")
+029  public static <T> Optional<T> of(T it) {
+030    if (it == null) return (Optional<T>) Optional.NONE;
+031    else return new Some(it);
+032  }
+033
+034  public abstract T get();
+035
+036  public abstract boolean isEmpty();
+037
+038  public boolean isDefined() {
+039    return !isEmpty();
+040  }
+041
+042  public static class Some<T> extends Optional<T> {
+043    private final T value;
+044
+045    Some(T value) {
+046      this.value = value;
+047    }
+048
+049    @Override
+050    public T get() {
+051      return value;
+052    }
+053
+054    @Override
+055    public boolean isEmpty() {
+056      return false;
+057    }
+058
+059    @Override
+060    public String toString() {
+061      return String.format("Some(%s)", value);
+062    }
+063  }
+064
+065  @Override
+066  public String toString() {
+067    return "None";
+068  }
+069}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.html new file mode 100644 index 0000000..e53bc7d --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/Optional.html @@ -0,0 +1,141 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003import java.util.NoSuchElementException;
+004
+005// simplest possible version of Scala's Option type
+006public abstract class Optional<T> {
+007
+008  private static final Optional<Object> NONE = new Optional<Object>() {
+009    @Override
+010    public Object get() {
+011      throw new NoSuchElementException(".get call on None!");
+012    }
+013
+014    @Override
+015    public boolean isEmpty() {
+016      return true;
+017    }
+018  };
+019
+020  private Optional() {
+021  }
+022
+023  @SuppressWarnings("unchecked")
+024  public static <T> Optional<T> empty() {
+025    return (Optional<T>) NONE;
+026  }
+027
+028  @SuppressWarnings("unchecked")
+029  public static <T> Optional<T> of(T it) {
+030    if (it == null) return (Optional<T>) Optional.NONE;
+031    else return new Some(it);
+032  }
+033
+034  public abstract T get();
+035
+036  public abstract boolean isEmpty();
+037
+038  public boolean isDefined() {
+039    return !isEmpty();
+040  }
+041
+042  public static class Some<T> extends Optional<T> {
+043    private final T value;
+044
+045    Some(T value) {
+046      this.value = value;
+047    }
+048
+049    @Override
+050    public T get() {
+051      return value;
+052    }
+053
+054    @Override
+055    public boolean isEmpty() {
+056      return false;
+057    }
+058
+059    @Override
+060    public String toString() {
+061      return String.format("Some(%s)", value);
+062    }
+063  }
+064
+065  @Override
+066  public String toString() {
+067    return "None";
+068  }
+069}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/PublisherVerificationRules.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/PublisherVerificationRules.html new file mode 100644 index 0000000..f073fa5 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/PublisherVerificationRules.html @@ -0,0 +1,117 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003
+004/**
+005 * Internal TCK use only.
+006 * Add / Remove tests for PublisherVerification here to make sure that they arre added/removed in the other places.
+007 */
+008public interface PublisherVerificationRules {
+009  void required_validate_maxElementsFromPublisher() throws Exception;
+010  void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception;
+011  void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable;
+012  void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable;
+013  void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable;
+014  void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable;
+015  void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable;
+016  void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable;
+017  void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable;
+018  void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable;
+019  void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable;
+020  void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable;
+021  void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable;
+022  void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable;
+023  void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable;
+024  void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable;
+025  void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable;
+026  void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable;
+027  void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable;
+028  void optional_spec111_maySupportMultiSubscribe() throws Throwable;
+029  void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable;
+030  void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable;
+031  void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable;
+032  void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable;
+033  void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable;
+034  void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception;
+035  void untested_spec305_cancelMustNotSynchronouslyPerformHeavyCompuatation() throws Exception;
+036  void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable;
+037  void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable;
+038  void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable;
+039  void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable;
+040  void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable;
+041  void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable;
+042  void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable;
+043  void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable;
+044  void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable;
+045}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html new file mode 100644 index 0000000..0f948ca --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBlackboxVerificationRules.html @@ -0,0 +1,105 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003/**
+004 * Internal TCK use only.
+005 * Add / Remove tests for SubscriberBlackboxVerification here to make sure that they arre added/removed in the other places.
+006 */
+007public interface SubscriberBlackboxVerificationRules {
+008  void required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() throws Throwable;
+009  void untested_spec202_blackbox_shouldAsynchronouslyDispatch() throws Exception;
+010  void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable;
+011  void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable;
+012  void untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception;
+013  void required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Exception;
+014  void untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception;
+015  void untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception;
+016  void untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable;
+017  void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable;
+018  void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable;
+019  void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable;
+020  void untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception;
+021  void untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() throws Throwable;
+022  void untested_spec213_blackbox_failingOnSignalInvocation() throws Exception;
+023  void required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+024  void required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+025  void required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+026  void untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() throws Exception;
+027  void untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable;
+028  void untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception;
+029  void untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception;
+030  void untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception;
+031  void untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception;
+032  void untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception;
+033}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html new file mode 100644 index 0000000..57f4282 --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberBufferOverflowException.html @@ -0,0 +1,90 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003public final class SubscriberBufferOverflowException extends RuntimeException {
+004  public SubscriberBufferOverflowException() {
+005  }
+006
+007  public SubscriberBufferOverflowException(String message) {
+008    super(message);
+009  }
+010
+011  public SubscriberBufferOverflowException(String message, Throwable cause) {
+012    super(message, cause);
+013  }
+014
+015  public SubscriberBufferOverflowException(Throwable cause) {
+016    super(cause);
+017  }
+018}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html new file mode 100644 index 0000000..664c2db --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/SubscriberWhiteboxVerificationRules.html @@ -0,0 +1,107 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003/**
+004 * Internal TCK use only.
+005 * Add / Remove tests for PublisherVerificaSubscriberWhiteboxVerification here to make sure that they arre added/removed in the other places.
+006 */
+007public interface SubscriberWhiteboxVerificationRules {
+008  void required_exerciseWhiteboxHappyPath() throws Throwable;
+009  void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable;
+010  void untested_spec202_shouldAsynchronouslyDispatch() throws Exception;
+011  void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable;
+012  void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable;
+013  void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception;
+014  void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable;
+015  void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception;
+016  void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception;
+017  void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable;
+018  void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable;
+019  void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable;
+020  void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable;
+021  void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable;
+022  void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception;
+023  void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable;
+024  void untested_spec213_failingOnSignalInvocation() throws Exception;
+025  void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+026  void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+027  void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+028  void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception;
+029  void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable;
+030  void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception;
+031  void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception;
+032  void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception;
+033  void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception;
+034  void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception;
+035}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/TestException.html b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/TestException.html new file mode 100644 index 0000000..2b2833b --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/src-html/org/reactivestreams/tck/support/TestException.html @@ -0,0 +1,83 @@ + + + +Source code + + + +
+
001package org.reactivestreams.tck.support;
+002
+003/**
+004 * Exception used by the TCK to signal failures.
+005 * May be thrown or signalled through {@link org.reactivestreams.Subscriber#onError(Throwable)}.
+006 */
+007public final class TestException extends RuntimeException {
+008  public TestException() {
+009    super("Test Exception: Boom!");
+010  }
+011}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/reactive-streams-tck-1.0.0-javadoc/stylesheet.css b/reactive-streams-tck-1.0.0-javadoc/stylesheet.css new file mode 100644 index 0000000..cebb4fd --- /dev/null +++ b/reactive-streams-tck-1.0.0-javadoc/stylesheet.css @@ -0,0 +1,574 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + +@import url('resources/fonts/dejavu.css'); + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D7A97; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D7A97; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D7A97; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; + width:100%; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} From 5ba107bddf97c2d332acc637f82bc7ba6c63f4d5 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 5 May 2015 13:33:57 +0200 Subject: [PATCH 2/2] Adding the announcement document. --- _includes/announce-1.0.0.md | 53 ++++++++++++++++++++++++++++++++ _includes/index.md | 60 +++++++++++-------------------------- announce-1.0.0.md | 5 ++++ 3 files changed, 76 insertions(+), 42 deletions(-) create mode 100644 _includes/announce-1.0.0.md create mode 100644 announce-1.0.0.md diff --git a/_includes/announce-1.0.0.md b/_includes/announce-1.0.0.md new file mode 100644 index 0000000..f605d63 --- /dev/null +++ b/_includes/announce-1.0.0.md @@ -0,0 +1,53 @@ +#Reactive Streams 1.0.0 is here! + + +It is with great pleasure that we—the *Reactive Streams Special Interest Group*—are announcing the immediate availability of the final form of _Reactive Streams_—after countless hours of prototyping, discussions, debate, evaluations, programming, testing, specifying requirements, documenting, and refining—we are confident that we have found the essential solution to the problem that we set out to solve: + +>[…] provide a standard for asynchronous stream processing with non-blocking back pressure.“ - [reactive-streams.org](http://www.reactive-streams.org) + +The artifacts, documentation and specifications are released under [Creative Commons Zero](http://creativecommons.org/publicdomain/zero/1.0) into the Public Domain. + +##Documentation + +* [Specification](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0#specification) +* [Java API Documentation](http://www.reactive-streams.org/reactive-streams-1.0.0-javadoc) +* [TCK README](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/tck/README.md) + +##Artifacts + +* `org.reactivestreams:reactive-streams:1.0.0`—the Reactive Streams interfaces + +* `org.reactivestreams:reactive-streams-tck:1.0.0`—the Reactive Streams TCK + +* `org.reactivestreams:reactive-streams-examples:1.0.0`—documented and verified example implementations to draw inspiration from. + + +## Implementations + + +We are also proud to let _Reactive Streams_ `1.0.0` be announced to the world accompanied with a multitude of compliant implementations verified by the TCK for 1.0.0, listed below in alphabetical order: + +* [Akka](http://akka.io/) Streams *(version `1.0-RC2`)* + * See this [Activator template](http://www.typesafe.com/activator/template/akka-stream-scala) and the [documentation](http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-RC2/index.html). +* [MongoDB](http://mongodb.org) *(version `1.0.0`)* + * For the documentation see [here](http://mongodb.github.io/mongo-java-driver-reactivestreams). +* [Ratpack](http://www.ratpack.io) *(version `0.9.16`)* + * See the [“Streams”](http://www.ratpack.io/manual/current/streams.html) chapter of the manual. +* Reactive Rabbit *(version `1.0.0`)* + * Driver for RabbitMQ/AMQP, see [here](https://github.com/ScalaConsultants/reactive-rabbit). +* [Reactor](http://projectreactor.io/) *(version `2.0.1.RELEASE`)* + * For the documentation see [here](http://projectreactor.io/docs/reference/streams.html). +* [RxJava](http://reactivex.io/) *(version `1.0.0`)* + * See [github.com/ReactiveX/RxJavaReactiveStreams](https://github.com/ReactiveX/RxJavaReactiveStreams). +* [Slick](http://slick.typesafe.com/) *(version `3.0.0`)* + * See the [“Streaming”](http://slick.typesafe.com/doc/3.0.0/dbio.html#streaming) section of the manual. +* [Vert.x 3.0](http://vertx.io) *(version `milestone-5a`)* + * Vert.x 3.0 is currently in alpha. The Reactive Streams implementation can be found [here](https://github.com/vert-x3/vertx-reactive-streams). + +##Credits + +We'd like to thank everyone involved, all [contributors](https://github.com/reactive-streams/reactive-streams-jvm/graphs/contributors), and everyone who has given feedback during the development of this project. + +*Warm regards, + +the Reactive Streams Special Interest Group* diff --git a/_includes/index.md b/_includes/index.md index 8b7676f..2dd1b63 100644 --- a/_includes/index.md +++ b/_includes/index.md @@ -24,27 +24,11 @@ We anticipate that acceptance of this Reactive Streams specification and experie The basic semantics define how the transmission of stream elements is regulated through back-pressure. How elements are transmitted, their representation during transfer, or how back-pressure is signaled is not part of this specification. -#### JVM Interfaces +#### JVM Interfaces (Completed) This working group applies the basic semantics to a set of programming interfaces whose main purpose is to allow the interoperation of different conforming implementations and language bindings for passing streams between objects and threads within the JVM, using the shared memory heap. -This work is performed in the [reactive-streams-jvm](https://github.com/reactive-streams/reactive-streams-jvm/) repository. - -#### JavaScript Interfaces - -This working group defines a minimal set of object properties for observing a stream of elements within a JavaScript runtime environment. The goal is to provide a testable specification that allows different implementations to interoperate within that same runtime environment. - -This work is performed in the [reactive-streams-js](https://github.com/reactive-streams/reactive-streams-js/) repository. - -#### Network Protocols - -This working group defines network protocols for passing reactive streams over various transport media that involve serialization and deserialization of the data elements. Examples of such transports are TCP, UDP, HTTP and WebSockets. - -This work is performed in the [reactive-streams-io](https://github.com/reactive-streams/reactive-streams-io/) repository. - -## Current State - -As of April 30, 2015 we have released version 1.0.0 of Reactive Streams for the JVM, including Java [API](/reactive-streams-1.0.0-javadoc), a textual [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification), a [TCK](/reactive-streams-tck-1.0.0-javadoc) and [implementation examples](/reactive-streams-examples-1.0.0-javadoc). Corresponding code artifacts are available on Maven Central: +As of *April 30, 2015* we have released version 1.0.0 of Reactive Streams for the JVM, including Java [API](/reactive-streams-1.0.0-javadoc), a textual [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification), a [TCK](/reactive-streams-tck-1.0.0-javadoc) and [implementation examples](/reactive-streams-examples-1.0.0-javadoc). Corresponding code artifacts are available on Maven Central: org.reactivestreams @@ -61,30 +45,22 @@ The source code for these is available on [github](https://github.com/reactive-s All artifacts and specifications are released under [Creative Commons Zero](http://creativecommons.org/publicdomain/zero/1.0) into the Public Domain. -### Implementations (sorted alphabetically) - -#### On the JVM - -* [Akka](http://akka.io/) Streams *(tested with TCK 1.0.0)* - * See this [Activator template](http://www.typesafe.com/activator/template/akka-stream-scala) and the [documentation](http://doc.akka.io/docs/akka-stream-and-http-experimental/1.0-M5/index.html). - * Please give [Feedback](http://doc.akka.io/docs/akka/current/project/issue-tracking.html) on the issue tracker. -* [MongoDB](http://mongodb.org) *(tested with TCK 1.0.0)* - * For the documentation see [here](http://mongodb.github.io/mongo-java-driver-reactivestreams). -* [Ratpack](http://www.ratpack.io) *(tested with TCK 1.0.0)* - * See the [“Streams”](http://www.ratpack.io/manual/current/streams.html) chapter of the manual. -* Reactive Rabbit *(tested with TCK 1.0.0.RC3)* - * Driver for RabbitMQ/AMQP. - * See [github.com/ScalaConsultants/reactive-rabbit](https://github.com/ScalaConsultants/reactive-rabbit). -* [Reactor](http://projectreactor.io/) *(tested with TCK 1.0.0)* - * For the documentation see [here](http://projectreactor.io/docs/reference/streams.html). -* [RxJava](http://reactivex.io/) *(tested with TCK 1.0.0)* - * See [github.com/ReactiveX/RxJavaReactiveStreams](https://github.com/ReactiveX/RxJavaReactiveStreams). -* [Slick](http://slick.typesafe.com/) *(tested with TCK 1.0.0)* - * Provides a *Publisher* for streaming database query results. - * See the ["Streaming"](http://slick.typesafe.com/doc/3.0.0-RC3/dbio.html#streaming) section of the manual. -* [Vert.x 3.0](http://vertx.io) *(tested with TCK 1.0.0)* - * Vert.x 3.0 is currently in alpha. The reactive streams implementation can be found [here](https://github.com/vert-x3/vertx-reactive-streams). +Read more about `Reactive Streams 1.0.0` for the JVM [here](announce-1.0.0.md). ##### A Note for Implementors -To get started implementing the draft specification, it is recommended to start by reading the [README](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md) and the [Java API documentation](/reactive-streams-1.0.0-javadoc), then taking a look at the [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification) then taking a look at the [TCK](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0/tck) and the [example implementations](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0/examples/src/main/java/org/reactivestreams/example/unicast). If you have an issue with any of the above, please take a look at [closed issues](https://github.com/reactive-streams/reactive-streams-jvm/issues?page=1&state=closed) and then open a [new issue](https://github.com/reactive-streams/reactive-streams-jvm/issues/new) if it has not already been answered. +To get started implementing the final specification, it is recommended to start by reading the [README](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md) and the [Java API documentation](/reactive-streams-1.0.0-javadoc), then taking a look at the [Specification](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification) then taking a look at the [TCK](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0/tck) and the [example implementations](https://github.com/reactive-streams/reactive-streams-jvm/tree/v1.0.0/examples/src/main/java/org/reactivestreams/example/unicast). If you have an issue with any of the above, please take a look at [closed issues](https://github.com/reactive-streams/reactive-streams-jvm/issues?page=1&state=closed) and then open a [new issue](https://github.com/reactive-streams/reactive-streams-jvm/issues/new) if it has not already been answered. + +This work was performed in the [reactive-streams-jvm](https://github.com/reactive-streams/reactive-streams-jvm/) repository. + +#### JavaScript Interfaces + +This working group defines a minimal set of object properties for observing a stream of elements within a JavaScript runtime environment. The goal is to provide a testable specification that allows different implementations to interoperate within that same runtime environment. + +This work is performed in the [reactive-streams-js](https://github.com/reactive-streams/reactive-streams-js/) repository. + +#### Network Protocols + +This working group defines network protocols for passing reactive streams over various transport media that involve serialization and deserialization of the data elements. Examples of such transports are TCP, UDP, HTTP and WebSockets. + +This work is performed in the [reactive-streams-io](https://github.com/reactive-streams/reactive-streams-io/) repository. diff --git a/announce-1.0.0.md b/announce-1.0.0.md new file mode 100644 index 0000000..7357c51 --- /dev/null +++ b/announce-1.0.0.md @@ -0,0 +1,5 @@ +--- +layout: index +--- + +{% include announce-1.0.0.md %}