Merge JDK-8200758-branch
authorherrick
Tue, 02 Jul 2019 12:03:49 -0400
branchJDK-8200758-branch
changeset 57448 ac7b7fe5f7d8
parent 57447 3fbe47a62ed0 (current diff)
parent 55548 1ba68bf27e27 (diff)
child 57450 82c78b40b39d
Merge
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -2142,7 +2142,7 @@
     // See whether biased locking is enabled and if so set it for this
     // klass.
     // Note that this must be done past the last potential blocking
-    // point / safepoint. We enable biased locking lazily using a
+    // point / safepoint. We might enable biased locking lazily using a
     // VM_Operation to iterate the SystemDictionary and installing the
     // biasable mark word into each InstanceKlass's prototype header.
     // To avoid race conditions where we accidentally miss enabling the
--- a/src/hotspot/share/gc/cms/cmsHeap.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/cms/cmsHeap.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -62,7 +62,7 @@
   }
 
   size_t used_in_bytes() {
-    return _space->used();
+    return _space->used_stable();
   }
 };
 
--- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -372,6 +372,8 @@
     )
   }
   _dictionary->set_par_lock(&_parDictionaryAllocLock);
+
+  _used_stable = 0;
 }
 
 // Like CompactibleSpace forward() but always calls cross_threshold() to
@@ -577,6 +579,14 @@
   return capacity() - free();
 }
 
+size_t CompactibleFreeListSpace::used_stable() const {
+  return _used_stable;
+}
+
+void CompactibleFreeListSpace::recalculate_used_stable() {
+  _used_stable = used();
+}
+
 size_t CompactibleFreeListSpace::free() const {
   // "MT-safe, but not MT-precise"(TM), if you will: i.e.
   // if you do this while the structures are in flux you
@@ -1374,6 +1384,9 @@
     debug_only(fc->mangleAllocated(size));
   }
 
+  // After allocation, recalculate used space and update used_stable
+  recalculate_used_stable();
+
   return res;
 }
 
--- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -192,6 +192,9 @@
   // Used to keep track of limit of sweep for the space
   HeapWord* _sweep_limit;
 
+  // Stable value of used().
+  size_t _used_stable;
+
   // Used to make the young collector update the mod union table
   MemRegionClosure* _preconsumptionDirtyCardClosure;
 
@@ -412,6 +415,17 @@
   // which overestimates the region by returning the entire
   // committed region (this is safe, but inefficient).
 
+  // Returns monotonically increasing stable used space bytes for CMS.
+  // This is required for jstat and other memory monitoring tools
+  // that might otherwise see inconsistent used space values during a garbage
+  // collection, promotion or allocation into compactibleFreeListSpace.
+  // The value returned by this function might be smaller than the
+  // actual value.
+  size_t used_stable() const;
+  // Recalculate and cache the current stable used() value. Only to be called
+  // in places where we can be sure that the result is stable.
+  void recalculate_used_stable();
+
   // Returns a subregion of the space containing all the objects in
   // the space.
   MemRegion used_region() const {
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -692,6 +692,10 @@
   return _cmsSpace->max_alloc_in_words() * HeapWordSize;
 }
 
+size_t ConcurrentMarkSweepGeneration::used_stable() const {
+  return cmsSpace()->used_stable();
+}
+
 size_t ConcurrentMarkSweepGeneration::max_available() const {
   return free() + _virtual_space.uncommitted_size();
 }
@@ -1523,6 +1527,8 @@
   FreelistLocker z(this);
   MetaspaceGC::compute_new_size();
   _cmsGen->compute_new_size_free_list();
+  // recalculate CMS used space after CMS collection
+  _cmsGen->cmsSpace()->recalculate_used_stable();
 }
 
 // A work method used by the foreground collector to do
@@ -2051,6 +2057,7 @@
 
   _capacity_at_prologue = capacity();
   _used_at_prologue = used();
+  _cmsSpace->recalculate_used_stable();
 
   // We enable promotion tracking so that card-scanning can recognize
   // which objects have been promoted during this GC and skip them.
@@ -2123,6 +2130,7 @@
   _eden_chunk_index = 0;
 
   size_t cms_used   = _cmsGen->cmsSpace()->used();
+  _cmsGen->cmsSpace()->recalculate_used_stable();
 
   // update performance counters - this uses a special version of
   // update_counters() that allows the utilization to be passed as a
@@ -2816,6 +2824,8 @@
     rp->enable_discovery();
     _collectorState = Marking;
   }
+
+  _cmsGen->cmsSpace()->recalculate_used_stable();
 }
 
 void CMSCollector::checkpointRootsInitialWork() {
@@ -4177,6 +4187,7 @@
     MutexLocker y(bitMapLock(),
                   Mutex::_no_safepoint_check_flag);
     checkpointRootsFinalWork();
+    _cmsGen->cmsSpace()->recalculate_used_stable();
   }
   verify_work_stacks_empty();
   verify_overflow_empty();
@@ -5336,9 +5347,14 @@
     // further below.
     {
       CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock());
+
       // Update heap occupancy information which is used as
       // input to soft ref clearing policy at the next gc.
       Universe::update_heap_info_at_gc();
+
+      // recalculate CMS used space after CMS collection
+      _cmsGen->cmsSpace()->recalculate_used_stable();
+
       _collectorState = Resizing;
     }
   }
@@ -5427,6 +5443,7 @@
     // Gather statistics on the young generation collection.
     collector()->stats().record_gc0_end(used());
   }
+  _cmsSpace->recalculate_used_stable();
 }
 
 void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* old_gen) {
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -1112,6 +1112,7 @@
   double occupancy() const { return ((double)used())/((double)capacity()); }
   size_t contiguous_available() const;
   size_t unsafe_max_alloc_nogc() const;
+  size_t used_stable() const;
 
   // over-rides
   MemRegion used_region_at_save_marks() const;
--- a/src/hotspot/share/gc/cms/gSpaceCounters.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/cms/gSpaceCounters.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -59,7 +59,7 @@
   }
 
   inline void update_used() {
-    _used->set_value(_gen->used());
+    _used->set_value(_gen->used_stable());
   }
 
   // special version of update_used() to allow the used value to be
@@ -103,7 +103,7 @@
     GenerationUsedHelper(Generation* g) : _gen(g) { }
 
     inline jlong take_sample() {
-      return _gen->used();
+      return _gen->used_stable();
     }
 };
 
--- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -267,6 +267,7 @@
   virtual bool has_load_barriers() const { return false; }
   virtual bool is_gc_barrier_node(Node* node) const { return false; }
   virtual Node* step_over_gc_barrier(Node* c) const { return c; }
+  virtual Node* step_over_gc_barrier_ctrl(Node* c) const { return c; }
 
   // Support for macro expanded GC barriers
   virtual void register_potential_barrier_node(Node* node) const { }
--- a/src/hotspot/share/gc/shared/generation.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/shared/generation.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -68,6 +68,12 @@
   return gch->old_gen_spec()->init_size();
 }
 
+// This is for CMS. It returns stable monotonic used space size.
+// Remove this when CMS is removed.
+size_t Generation::used_stable() const {
+  return used();
+}
+
 size_t Generation::max_capacity() const {
   return reserved().byte_size();
 }
--- a/src/hotspot/share/gc/shared/generation.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/shared/generation.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -156,6 +156,7 @@
   virtual size_t capacity() const = 0;  // The maximum number of object bytes the
                                         // generation can currently hold.
   virtual size_t used() const = 0;      // The number of used bytes in the gen.
+  virtual size_t used_stable() const;   // The number of used bytes for memory monitoring tools.
   virtual size_t free() const = 0;      // The number of free bytes in the gen.
 
   // Support for java.lang.Runtime.maxMemory(); see CollectedHeap.
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -41,11 +41,11 @@
 #include "services/management.hpp"
 
 ShenandoahSerialRoot::ShenandoahSerialRoot(ShenandoahSerialRoot::OopsDo oops_do, ShenandoahPhaseTimings::GCParPhases phase) :
-  _claimed(false), _oops_do(oops_do), _phase(phase) {
+  _oops_do(oops_do), _phase(phase) {
 }
 
 void ShenandoahSerialRoot::oops_do(OopClosure* cl, uint worker_id) {
-  if (!_claimed && Atomic::cmpxchg(true, &_claimed, false) == false) {
+  if (_claimed.try_set()) {
     ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
     ShenandoahWorkerTimingsTracker timer(worker_times, _phase, worker_id);
     _oops_do(cl);
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -36,7 +36,7 @@
 public:
   typedef void (*OopsDo)(OopClosure*);
 private:
-  volatile bool                             _claimed;
+  ShenandoahSharedFlag                      _claimed;
   const OopsDo                              _oops_do;
   const ShenandoahPhaseTimings::GCParPhases _phase;
 
--- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -364,10 +364,6 @@
   diagnostic(bool, ShenandoahLoadRefBarrier, true,                          \
           "Turn on/off load-reference barriers in Shenandoah")              \
                                                                             \
-  diagnostic(bool, ShenandoahStoreCheck, false,                             \
-          "Emit additional code that checks objects are written to only"    \
-          " in to-space")                                                   \
-                                                                            \
   experimental(bool, ShenandoahConcurrentScanCodeRoots, true,               \
           "Scan code roots concurrently, instead of during a pause")        \
                                                                             \
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -522,7 +522,7 @@
   Node* in_val = barrier->in(LoadBarrierNode::Oop);
   Node* in_adr = barrier->in(LoadBarrierNode::Address);
 
-  Node* out_ctrl = barrier->proj_out_or_null(LoadBarrierNode::Control);
+  Node* out_ctrl = barrier->proj_out(LoadBarrierNode::Control);
   Node* out_res = barrier->proj_out(LoadBarrierNode::Oop);
 
   assert(barrier->in(LoadBarrierNode::Oop) != NULL, "oop to loadbarrier node cannot be null");
@@ -552,9 +552,8 @@
   result_phi->set_req(1, new_loadp);
   result_phi->set_req(2, barrier->in(LoadBarrierNode::Oop));
 
-  if (out_ctrl != NULL) {
-    igvn.replace_node(out_ctrl, result_region);
-  }
+
+  igvn.replace_node(out_ctrl, result_region);
   igvn.replace_node(out_res, result_phi);
 
   assert(barrier->outcnt() == 0,"LoadBarrier macro node has non-null outputs after expansion!");
@@ -640,6 +639,22 @@
   return c;
 }
 
+Node* ZBarrierSetC2::step_over_gc_barrier_ctrl(Node* c) const {
+  Node* node = c;
+
+  // 1. This step follows potential ctrl projections of a load barrier before expansion
+  if (node->is_Proj()) {
+    node = node->in(0);
+  }
+
+  // 2. This step checks for unexpanded load barriers
+  if (node->is_LoadBarrier()) {
+    return node->in(LoadBarrierNode::Control);
+  }
+
+  return c;
+}
+
 bool ZBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const {
   return type == T_OBJECT || type == T_ARRAY;
 }
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -182,6 +182,7 @@
   virtual bool has_load_barriers() const { return true; }
   virtual bool is_gc_barrier_node(Node* node) const;
   virtual Node* step_over_gc_barrier(Node* c) const;
+  virtual Node* step_over_gc_barrier_ctrl(Node* c) const;
 
   virtual void register_potential_barrier_node(Node* node) const;
   virtual void unregister_potential_barrier_node(Node* node) const;
--- a/src/hotspot/share/memory/filemap.hpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/memory/filemap.hpp	Tue Jul 02 12:03:49 2019 -0400
@@ -380,12 +380,12 @@
   char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(NULL);
   int   num_paths(const char* path) NOT_CDS_RETURN_(0);
   GrowableArray<char*>* create_path_array(const char* path) NOT_CDS_RETURN_(NULL);
-  bool  fail(const char* msg, const char* name) NOT_CDS_RETURN_(FALSE);
+  bool  fail(const char* msg, const char* name) NOT_CDS_RETURN_(false);
   bool  check_paths(int shared_path_start_idx,
                     int num_paths,
-                    GrowableArray<char*>* rp_array) NOT_CDS_RETURN_(FALSE);
-  bool  validate_boot_class_paths() NOT_CDS_RETURN_(FALSE);
-  bool  validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(FALSE);
+                    GrowableArray<char*>* rp_array) NOT_CDS_RETURN_(false);
+  bool  validate_boot_class_paths() NOT_CDS_RETURN_(false);
+  bool  validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false);
   bool  map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
                       bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
   bool  region_crc_check(char* buf, size_t size, int expected_crc) NOT_CDS_RETURN_(false);
--- a/src/hotspot/share/memory/metaspace.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/memory/metaspace.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -1588,71 +1588,6 @@
 
 /////////////// Unit tests ///////////////
 
-#ifndef PRODUCT
-
-class TestMetaspaceUtilsTest : AllStatic {
- public:
-  static void test_reserved() {
-    size_t reserved = MetaspaceUtils::reserved_bytes();
-
-    assert(reserved > 0, "assert");
-
-    size_t committed  = MetaspaceUtils::committed_bytes();
-    assert(committed <= reserved, "assert");
-
-    size_t reserved_metadata = MetaspaceUtils::reserved_bytes(Metaspace::NonClassType);
-    assert(reserved_metadata > 0, "assert");
-    assert(reserved_metadata <= reserved, "assert");
-
-    if (UseCompressedClassPointers) {
-      size_t reserved_class    = MetaspaceUtils::reserved_bytes(Metaspace::ClassType);
-      assert(reserved_class > 0, "assert");
-      assert(reserved_class < reserved, "assert");
-    }
-  }
-
-  static void test_committed() {
-    size_t committed = MetaspaceUtils::committed_bytes();
-
-    assert(committed > 0, "assert");
-
-    size_t reserved  = MetaspaceUtils::reserved_bytes();
-    assert(committed <= reserved, "assert");
-
-    size_t committed_metadata = MetaspaceUtils::committed_bytes(Metaspace::NonClassType);
-    assert(committed_metadata > 0, "assert");
-    assert(committed_metadata <= committed, "assert");
-
-    if (UseCompressedClassPointers) {
-      size_t committed_class    = MetaspaceUtils::committed_bytes(Metaspace::ClassType);
-      assert(committed_class > 0, "assert");
-      assert(committed_class < committed, "assert");
-    }
-  }
-
-  static void test_virtual_space_list_large_chunk() {
-    VirtualSpaceList* vs_list = new VirtualSpaceList(os::vm_allocation_granularity());
-    MutexLocker cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag);
-    // A size larger than VirtualSpaceSize (256k) and add one page to make it _not_ be
-    // vm_allocation_granularity aligned on Windows.
-    size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord));
-    large_size += (os::vm_page_size()/BytesPerWord);
-    vs_list->get_new_chunk(large_size, 0);
-  }
-
-  static void test() {
-    test_reserved();
-    test_committed();
-    test_virtual_space_list_large_chunk();
-  }
-};
-
-void TestMetaspaceUtils_test() {
-  TestMetaspaceUtilsTest::test();
-}
-
-#endif // !PRODUCT
-
 struct chunkmanager_statistics_t {
   int num_specialized_chunks;
   int num_small_chunks;
--- a/src/hotspot/share/opto/macro.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/opto/macro.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -1008,8 +1008,17 @@
         assert(init->outcnt() <= 2, "only a control and memory projection expected");
         Node *ctrl_proj = init->proj_out_or_null(TypeFunc::Control);
         if (ctrl_proj != NULL) {
-           assert(init->in(TypeFunc::Control) == _fallthroughcatchproj, "allocation control projection");
-          _igvn.replace_node(ctrl_proj, _fallthroughcatchproj);
+          _igvn.replace_node(ctrl_proj, init->in(TypeFunc::Control));
+#ifdef ASSERT
+          BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
+          Node* tmp = init->in(TypeFunc::Control);
+          while (bs->is_gc_barrier_node(tmp)) {
+            Node* tmp2 = bs->step_over_gc_barrier_ctrl(tmp);
+            assert(tmp != tmp2, "Must make progress");
+            tmp = tmp2;
+          }
+          assert(tmp == _fallthroughcatchproj, "allocation control projection");
+#endif
         }
         Node *mem_proj = init->proj_out_or_null(TypeFunc::Memory);
         if (mem_proj != NULL) {
--- a/src/hotspot/share/prims/jvmti.xsl	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/prims/jvmti.xsl	Tue Jul 02 12:03:49 2019 -0400
@@ -62,37 +62,96 @@
     <div class="centered" role="banner">
       <xsl:apply-templates select="title"/>
     </div>
-    <ul role="navigation">
-      <li>
-        <a href="#SpecificationIntro"><b>Introduction</b></a>
-        <ul>
-          <xsl:for-each select="intro">
+    <nav>
+      <ul>
+        <li>
+          <a href="#SpecificationIntro"><b>Introduction</b></a>
+          <ul>
+            <xsl:for-each select="intro">
+              <li>
+                <a>
+                  <xsl:attribute name="href">#<xsl:value-of select="@id"/>
+                  </xsl:attribute>
+                  <b><xsl:value-of select="@label"/></b>
+                </a>
+              </li>
+            </xsl:for-each>
+          </ul>
+        </li>
+        <li>
+          <a href="#FunctionSection"><b>Functions</b></a>
+          <ul>
+            <xsl:for-each select="functionsection/intro">
+              <li>
+                <a>
+                  <xsl:attribute name="href">#<xsl:value-of select="@id"/>
+                  </xsl:attribute>
+                  <b><xsl:value-of select="@label"/></b>
+                </a>
+              </li>
+            </xsl:for-each>
+            <li>
+              <a href="#FunctionIndex"><b>Function Index</b></a>
+              <ul>
+                <xsl:for-each select="functionsection/category">
+                  <li>
+                    <a>
+                      <xsl:attribute name="href">#<xsl:value-of select="@id"/>
+                      </xsl:attribute>
+                      <b><xsl:value-of select="@label"/></b>
+                    </a>
+                  </li>
+                </xsl:for-each>
+              </ul>
+            </li>
+            <li>
+              <a href="#ErrorSection"><b>Error Codes</b></a>
+            </li>
+          </ul>
+        </li>
+        <li>
+          <a href="#EventSection"><b>Events</b></a>
+          <ul>
+            <li>
+              <a href="#EventIndex"><b>Event Index</b></a>
+            </li>
+          </ul>
+        </li>
+        <li>
+          <a href="#DataSection"><b>Data Types</b></a>
+          <ul>
+            <xsl:for-each select="//basetypes">
             <li>
               <a>
-                <xsl:attribute name="href">#<xsl:value-of select="@id"/>
-                </xsl:attribute>
-                <b><xsl:value-of select="@label"/></b>
+                <xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
+                <b>
+                  <xsl:value-of select="@label"/>
+                </b>
               </a>
             </li>
-          </xsl:for-each>
-        </ul>
-      </li>
-      <li>
-        <a href="#FunctionSection"><b>Functions</b></a>
-        <ul>
-          <xsl:for-each select="functionsection/intro">
+            </xsl:for-each>
+            <li>
+              <a href="#StructureTypeDefinitions"><b>Structure Type Definitions</b></a>
+            </li>
+            <li>
+              <a href="#FunctionTypeDefinitions"><b>Function Type Definitions</b></a>
+            </li>
+            <li>
+              <a href="#EnumerationDefinitions"><b>Enumeration Definitions</b></a>
+            </li>
             <li>
-              <a>
-                <xsl:attribute name="href">#<xsl:value-of select="@id"/>
-                </xsl:attribute>
-                <b><xsl:value-of select="@label"/></b>
-              </a>
+              <a href="#FunctionTable"><b>Function Table</b></a>
             </li>
-          </xsl:for-each>
+          </ul>
+        </li>
+        <li>
+          <a href="#ConstantIndex"><b>Constant Index</b></a>
+        </li>
+        <xsl:if test="$development = 'Show'">
           <li>
-            <a href="#FunctionIndex"><b>Function Index</b></a>
+            <a href="#SpecificationIssues"><b>Issues</b></a>
             <ul>
-              <xsl:for-each select="functionsection/category">
+              <xsl:for-each select="issuessection/intro">
                 <li>
                   <a>
                     <xsl:attribute name="href">#<xsl:value-of select="@id"/>
@@ -103,69 +162,12 @@
               </xsl:for-each>
             </ul>
           </li>
-          <li>
-            <a href="#ErrorSection"><b>Error Codes</b></a>
-          </li>
-        </ul>
-      </li>
-      <li>
-        <a href="#EventSection"><b>Events</b></a>
-        <ul>
-          <li>
-            <a href="#EventIndex"><b>Event Index</b></a>
-          </li>
-        </ul>
-      </li>
-      <li>
-        <a href="#DataSection"><b>Data Types</b></a>
-        <ul>
-          <xsl:for-each select="//basetypes">
-          <li>
-            <a>
-              <xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
-              <b>
-                <xsl:value-of select="@label"/>
-              </b>
-            </a>
-          </li>
-          </xsl:for-each>
-          <li>
-            <a href="#StructureTypeDefinitions"><b>Structure Type Definitions</b></a>
-          </li>
-          <li>
-            <a href="#FunctionTypeDefinitions"><b>Function Type Definitions</b></a>
-          </li>
-          <li>
-            <a href="#EnumerationDefinitions"><b>Enumeration Definitions</b></a>
-          </li>
-          <li>
-            <a href="#FunctionTable"><b>Function Table</b></a>
-          </li>
-        </ul>
-      </li>
-      <li>
-        <a href="#ConstantIndex"><b>Constant Index</b></a>
-      </li>
-      <xsl:if test="$development = 'Show'">
+        </xsl:if>
         <li>
-          <a href="#SpecificationIssues"><b>Issues</b></a>
-          <ul>
-            <xsl:for-each select="issuessection/intro">
-              <li>
-                <a>
-                  <xsl:attribute name="href">#<xsl:value-of select="@id"/>
-                  </xsl:attribute>
-                  <b><xsl:value-of select="@label"/></b>
-                </a>
-              </li>
-            </xsl:for-each>
-          </ul>
+          <a href="#ChangeHistory"><b>Change History</b></a>
         </li>
-      </xsl:if>
-      <li>
-        <a href="#ChangeHistory"><b>Change History</b></a>
-      </li>
-    </ul>
+      </ul>
+    </nav>
     <!-- end table of contents, begin body -->
     <div role="main">
     <div class="sep"/>
@@ -212,11 +214,11 @@
     <h1>
       <xsl:apply-templates/>
     </h1>
-    <h3>
+    <h2>
       <xsl:value-of select="@subtitle"/>
       <xsl:text> </xsl:text>
       <xsl:call-template name="showbasicversion"/>
-    </h3>
+    </h2>
 </xsl:template>
 
 <xsl:template match="functionsection">
@@ -363,7 +365,7 @@
       </td>
     </tr>
     <tr>
-      <td >
+      <td>
         <xsl:apply-templates select="." mode="phaseinfo"/>
       </td>
       <td>
@@ -642,12 +644,12 @@
 </xsl:template>
 
 <xsl:template match="capabilitiestypedef|typedef|uniontypedef">
-  <h4>
+  <h3>
     <xsl:attribute name="id">
       <xsl:value-of select="@id"/>
     </xsl:attribute>
     <xsl:value-of select="@label"/>
-  </h4>
+  </h3>
   <xsl:apply-templates select="." mode="description"/>
   <blockquote>
     <xsl:apply-templates select="." mode="code"/>
@@ -1951,12 +1953,12 @@
   <xsl:if test="@id!=''">
     <xsl:choose>
       <xsl:when test="@label!=''">
-        <h4>
+        <h3>
           <xsl:attribute name="id">
             <xsl:value-of select="@id"/>
           </xsl:attribute>
           <xsl:value-of select="@label"/>
-        </h4>
+        </h3>
       </xsl:when>
       <xsl:otherwise>
         <a>
--- a/src/hotspot/share/prims/whitebox.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/prims/whitebox.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -242,7 +242,6 @@
 void TestReservedSpace_test();
 void TestReserveMemorySpecial_test();
 void TestVirtualSpace_test();
-void TestMetaspaceUtils_test();
 #endif
 
 WB_ENTRY(void, WB_RunMemoryUnitTests(JNIEnv* env, jobject o))
@@ -250,7 +249,6 @@
   TestReservedSpace_test();
   TestReserveMemorySpecial_test();
   TestVirtualSpace_test();
-  TestMetaspaceUtils_test();
 #endif
 WB_END
 
--- a/src/hotspot/share/runtime/biasedLocking.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/runtime/biasedLocking.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -52,23 +52,24 @@
   k->set_prototype_header(markOopDesc::biased_locking_prototype());
 }
 
+static void enable_biased_locking() {
+  _biased_locking_enabled = true;
+  log_info(biasedlocking)("Biased locking enabled");
+}
+
 class VM_EnableBiasedLocking: public VM_Operation {
- private:
-  bool _is_cheap_allocated;
  public:
-  VM_EnableBiasedLocking(bool is_cheap_allocated) { _is_cheap_allocated = is_cheap_allocated; }
+  VM_EnableBiasedLocking() {}
   VMOp_Type type() const          { return VMOp_EnableBiasedLocking; }
-  Mode evaluation_mode() const    { return _is_cheap_allocated ? _async_safepoint : _safepoint; }
-  bool is_cheap_allocated() const { return _is_cheap_allocated; }
+  Mode evaluation_mode() const    { return _async_safepoint; }
+  bool is_cheap_allocated() const { return true; }
 
   void doit() {
     // Iterate the class loader data dictionaries enabling biased locking for all
     // currently loaded classes.
     ClassLoaderDataGraph::dictionary_classes_do(enable_biased_locking);
     // Indicate that future instances should enable it as well
-    _biased_locking_enabled = true;
-
-    log_info(biasedlocking)("Biased locking enabled");
+    enable_biased_locking();
   }
 
   bool allow_nested_vm_operations() const        { return false; }
@@ -83,7 +84,7 @@
   virtual void task() {
     // Use async VM operation to avoid blocking the Watcher thread.
     // VM Thread will free C heap storage.
-    VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking(true);
+    VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking();
     VMThread::execute(op);
 
     // Reclaim our storage and disenroll ourself
@@ -93,27 +94,29 @@
 
 
 void BiasedLocking::init() {
-  // If biased locking is enabled, schedule a task to fire a few
-  // seconds into the run which turns on biased locking for all
-  // currently loaded classes as well as future ones. This is a
-  // workaround for startup time regressions due to a large number of
-  // safepoints being taken during VM startup for bias revocation.
-  // Ideally we would have a lower cost for individual bias revocation
-  // and not need a mechanism like this.
+  // If biased locking is enabled and BiasedLockingStartupDelay is set,
+  // schedule a task to fire after the specified delay which turns on
+  // biased locking for all currently loaded classes as well as future
+  // ones. This could be a workaround for startup time regressions
+  // due to large number of safepoints being taken during VM startup for
+  // bias revocation.
   if (UseBiasedLocking) {
     if (BiasedLockingStartupDelay > 0) {
       EnableBiasedLockingTask* task = new EnableBiasedLockingTask(BiasedLockingStartupDelay);
       task->enroll();
     } else {
-      VM_EnableBiasedLocking op(false);
-      VMThread::execute(&op);
+      enable_biased_locking();
     }
   }
 }
 
 
 bool BiasedLocking::enabled() {
-  return _biased_locking_enabled;
+  assert(UseBiasedLocking, "precondition");
+  // We check "BiasedLockingStartupDelay == 0" here to cover the
+  // possibility of calls to BiasedLocking::enabled() before
+  // BiasedLocking::init().
+  return _biased_locking_enabled || BiasedLockingStartupDelay == 0;
 }
 
 // Returns MonitorInfos for all objects locked on this thread in youngest to oldest order
--- a/src/hotspot/share/runtime/deoptimization.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/runtime/deoptimization.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -840,6 +840,15 @@
     }
     return NULL;
   }
+  oop lookup_raw(intptr_t raw_value) {
+    // Have to cast to avoid little/big-endian problems.
+    if (sizeof(PrimitiveType) > sizeof(jint)) {
+      jlong value = (jlong)raw_value;
+      return lookup(value);
+    }
+    PrimitiveType value = (PrimitiveType)*((jint*)&raw_value);
+    return lookup(value);
+  }
 };
 
 typedef BoxCache<jint, java_lang_Integer_IntegerCache, java_lang_Integer> IntegerBoxCache;
@@ -878,6 +887,11 @@
     }
     return _singleton;
   }
+  oop lookup_raw(intptr_t raw_value) {
+    // Have to cast to avoid little/big-endian problems.
+    jboolean value = (jboolean)*((jint*)&raw_value);
+    return lookup(value);
+  }
   oop lookup(jboolean value) {
     if (value != 0) {
       return JNIHandles::resolve_non_null(_true_cache);
@@ -892,18 +906,14 @@
    Klass* k = java_lang_Class::as_Klass(bv->klass()->as_ConstantOopReadValue()->value()());
    BasicType box_type = SystemDictionary::box_klass_type(k);
    if (box_type != T_OBJECT) {
-     StackValue* value = StackValue::create_stack_value(fr, reg_map, bv->field_at(0));
+     StackValue* value = StackValue::create_stack_value(fr, reg_map, bv->field_at(box_type == T_LONG ? 1 : 0));
      switch(box_type) {
-       case T_INT:     return IntegerBoxCache::singleton(THREAD)->lookup(value->get_int());
-       case T_LONG: {
-                       StackValue* low = StackValue::create_stack_value(fr, reg_map, bv->field_at(1));
-                       jlong res = (jlong)low->get_int();
-                       return LongBoxCache::singleton(THREAD)->lookup(res);
-                     }
-       case T_CHAR:    return CharacterBoxCache::singleton(THREAD)->lookup(value->get_int());
-       case T_SHORT:   return ShortBoxCache::singleton(THREAD)->lookup(value->get_int());
-       case T_BYTE:    return ByteBoxCache::singleton(THREAD)->lookup(value->get_int());
-       case T_BOOLEAN: return BooleanBoxCache::singleton(THREAD)->lookup(value->get_int());
+       case T_INT:     return IntegerBoxCache::singleton(THREAD)->lookup_raw(value->get_int());
+       case T_CHAR:    return CharacterBoxCache::singleton(THREAD)->lookup_raw(value->get_int());
+       case T_SHORT:   return ShortBoxCache::singleton(THREAD)->lookup_raw(value->get_int());
+       case T_BYTE:    return ByteBoxCache::singleton(THREAD)->lookup_raw(value->get_int());
+       case T_BOOLEAN: return BooleanBoxCache::singleton(THREAD)->lookup_raw(value->get_int());
+       case T_LONG:    return LongBoxCache::singleton(THREAD)->lookup_raw(value->get_int());
        default:;
      }
    }
--- a/src/hotspot/share/runtime/flags/jvmFlag.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -1475,19 +1475,13 @@
 
 void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, bool skipDefaults) {
   // Print the flags sorted by name
-  // note: this method is called before the thread structure is in place
-  //       which means resource allocation cannot be used.
+  // Note: This method may be called before the thread structure is in place
+  //       which means resource allocation cannot be used. Also, it may be
+  //       called as part of error reporting, so handle native OOMs gracefully.
 
   // The last entry is the null entry.
   const size_t length = JVMFlag::numFlags - 1;
 
-  // Sort
-  JVMFlag** array = NEW_C_HEAP_ARRAY(JVMFlag*, length, mtArguments);
-  for (size_t i = 0; i < length; i++) {
-    array[i] = &flagTable[i];
-  }
-  qsort(array, length, sizeof(JVMFlag*), compare_flags);
-
   // Print
   if (!printRanges) {
     out->print_cr("[Global flags]");
@@ -1495,12 +1489,28 @@
     out->print_cr("[Global flags ranges]");
   }
 
-  for (size_t i = 0; i < length; i++) {
-    if (array[i]->is_unlocked() && !(skipDefaults && array[i]->is_default())) {
-      array[i]->print_on(out, withComments, printRanges);
+  // Sort
+  JVMFlag** array = NEW_C_HEAP_ARRAY_RETURN_NULL(JVMFlag*, length, mtArguments);
+  if (array != NULL) {
+    for (size_t i = 0; i < length; i++) {
+      array[i] = &flagTable[i];
+    }
+    qsort(array, length, sizeof(JVMFlag*), compare_flags);
+
+    for (size_t i = 0; i < length; i++) {
+      if (array[i]->is_unlocked() && !(skipDefaults && array[i]->is_default())) {
+        array[i]->print_on(out, withComments, printRanges);
+      }
+    }
+    FREE_C_HEAP_ARRAY(JVMFlag*, array);
+  } else {
+    // OOM? Print unsorted.
+    for (size_t i = 0; i < length; i++) {
+      if (flagTable[i].is_unlocked() && !(skipDefaults && flagTable[i].is_default())) {
+        flagTable[i].print_on(out, withComments, printRanges);
+      }
     }
   }
-  FREE_C_HEAP_ARRAY(JVMFlag*, array);
 }
 
 void JVMFlag::printError(bool verbose, const char* msg, ...) {
--- a/src/java.base/share/classes/java/lang/Throwable.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/java.base/share/classes/java/lang/Throwable.java	Tue Jul 02 12:03:49 2019 -0400
@@ -693,7 +693,7 @@
                                          Set<Throwable> dejaVu) {
         assert Thread.holdsLock(s.lock());
         if (dejaVu.contains(this)) {
-            s.println("\t[CIRCULAR REFERENCE:" + this + "]");
+            s.println(prefix + caption + "[CIRCULAR REFERENCE: " + this + "]");
         } else {
             dejaVu.add(this);
             // Compute number of frames in common between this and enclosing trace
--- a/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java	Tue Jul 02 12:03:49 2019 -0400
@@ -249,9 +249,15 @@
             switch (requestID) {
             case FIRST_DAY_OF_WEEK:
                 value = calendarDataProvider.getFirstDayOfWeek(locale);
+                if (value == 0) {
+                    value = MONDAY; // default for the world ("001")
+                }
                 break;
             case MINIMAL_DAYS_IN_FIRST_WEEK:
                 value = calendarDataProvider.getMinimalDaysInFirstWeek(locale);
+                if (value == 0) {
+                    value = 1; // default for the world ("001")
+                }
                 break;
             default:
                 throw new InternalError("invalid requestID: " + requestID);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jul 02 12:03:49 2019 -0400
@@ -1447,6 +1447,9 @@
         if (tree.cases.isEmpty()) {
             log.error(tree.pos(),
                       Errors.SwitchExpressionEmpty);
+        } else if (caseTypes.isEmpty()) {
+            log.error(tree.pos(),
+                      Errors.SwitchExpressionNoResultExpressions);
         }
 
         Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(caseTypePositions.toList(), caseTypes.toList()) : pt();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Jul 02 12:03:49 2019 -0400
@@ -223,6 +223,9 @@
 compiler.err.switch.expression.empty=\
     switch expression does not have any case clauses
 
+compiler.err.switch.expression.no.result.expressions=\
+    switch expression does not have any result expressions
+
 # 0: name
 compiler.err.call.must.be.first.stmt.in.ctor=\
     call to {0} must be first statement in constructor
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java	Tue Jul 02 12:03:49 2019 -0400
@@ -395,33 +395,49 @@
                 ("Unsupported digest algorithm in Signature parameters: " +
                  digestAlgorithm);
         }
+
         if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) {
             throw new InvalidAlgorithmParameterException("Only supports MGF1");
         }
+
+        // defaults to the digest algorithm unless overridden
+        String mgfDigestAlgo = digestAlgorithm;
+        AlgorithmParameterSpec mgfParams = params.getMGFParameters();
+        if (mgfParams != null) {
+            if (!(mgfParams instanceof MGF1ParameterSpec)) {
+                throw new InvalidAlgorithmParameterException
+                        ("Only MGF1ParameterSpec is supported");
+            }
+            mgfDigestAlgo = ((MGF1ParameterSpec)mgfParams).getDigestAlgorithm();
+        }
+
         if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
             throw new InvalidAlgorithmParameterException
                 ("Only supports TrailerFieldBC(1)");
         }
+
         int saltLen = params.getSaltLength();
         if (this.p11Key != null) {
-            int maxSaltLen = ((this.p11Key.length() + 7) >> 3) - digestLen.intValue() - 2;
+            int maxSaltLen = ((this.p11Key.length() + 7) >> 3) -
+                    digestLen.intValue() - 2;
 
             if (DEBUG) {
                 System.out.println("Max saltLen = " + maxSaltLen);
                 System.out.println("Curr saltLen = " + saltLen);
             }
             if (maxSaltLen < 0 || saltLen > maxSaltLen) {
-                throw new InvalidAlgorithmParameterException("Invalid with current key size");
+                throw new InvalidAlgorithmParameterException
+                        ("Invalid with current key size");
             }
-        } else {
-            if (DEBUG) System.out.println("No key available for validating saltLen");
+        } else if (DEBUG) {
+            System.out.println("No key available for validating saltLen");
         }
 
         // validated, now try to store the parameter internally
         try {
             this.mechanism.setParameter(
                     new CK_RSA_PKCS_PSS_PARAMS(digestAlgorithm, "MGF1",
-                        digestAlgorithm, saltLen));
+                            mgfDigestAlgo, saltLen));
             this.sigParams = params;
         } catch (IllegalArgumentException iae) {
             throw new InvalidAlgorithmParameterException(iae);
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS.java	Tue Jul 02 12:03:49 2019 -0400
@@ -57,7 +57,7 @@
             throw new ProviderException("Only MGF1 is supported");
         }
         // no dash in PKCS#11 mechanism names
-        this.mgf = Functions.getMGFId("CKG_MGF1_" + hashAlg.replaceFirst("-", ""));
+        this.mgf = Functions.getMGFId("CKG_MGF1_" + mgfHash.replaceFirst("-", ""));
         this.sLen = sLen;
     }
 
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Tue Jul 02 12:03:49 2019 -0400
@@ -475,7 +475,9 @@
                 methodData = new HotSpotMethodData(metaspaceMethodData, this);
                 String methodDataFilter = Option.TraceMethodDataFilter.getString();
                 if (methodDataFilter != null && this.format("%H.%n").contains(methodDataFilter)) {
-                    System.out.println(methodData.toString());
+                    String line = methodData.toString() + System.lineSeparator();
+                    byte[] lineBytes = line.getBytes();
+                    CompilerToVM.compilerToVM().writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
                 }
             }
         }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Tue Jul 02 12:03:49 2019 -0400
@@ -573,6 +573,10 @@
             // The type isn't known to implement the method.
             return null;
         }
+        if (resolvedMethod.canBeStaticallyBound()) {
+            // No assumptions are required.
+            return new AssumptionResult<>(resolvedMethod);
+        }
 
         if (resolvedMethod.canBeStaticallyBound()) {
             // No assumptions are required.
--- a/test/hotspot/jtreg/gc/shenandoah/TestEvilSyncBug.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/hotspot/jtreg/gc/shenandoah/TestEvilSyncBug.java	Tue Jul 02 12:03:49 2019 -0400
@@ -61,7 +61,6 @@
                             "-XX:+UnlockDiagnosticVMOptions",
                             "-XX:+UseShenandoahGC",
                             "-XX:ShenandoahGCHeuristics=aggressive",
-                            "-XX:+ShenandoahStoreCheck",
                             "TestEvilSyncBug", "test");
                     OutputAnalyzer output = new OutputAnalyzer(pb.start());
                     output.shouldHaveExitValue(0);
--- a/test/hotspot/jtreg/gc/shenandoah/TestVerifyJCStress.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/hotspot/jtreg/gc/shenandoah/TestVerifyJCStress.java	Tue Jul 02 12:03:49 2019 -0400
@@ -30,31 +30,31 @@
  *          java.management
  * @run main/othervm  -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions
  *                    -XX:+UseShenandoahGC -Xmx1g -Xms1g
- *                    -XX:+ShenandoahStoreCheck -XX:+ShenandoahVerify -XX:+VerifyObjectEquals
+ *                    -XX:+ShenandoahVerify -XX:+VerifyObjectEquals
  *                    -XX:ShenandoahGCHeuristics=passive -XX:+ShenandoahDegeneratedGC
  *                    TestVerifyJCStress
  *
  * @run main/othervm  -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions
  *                    -XX:+UseShenandoahGC -Xmx1g -Xms1g
- *                    -XX:+ShenandoahStoreCheck -XX:+ShenandoahVerify -XX:+VerifyObjectEquals
+ *                    -XX:+ShenandoahVerify -XX:+VerifyObjectEquals
  *                    -XX:ShenandoahGCHeuristics=passive -XX:-ShenandoahDegeneratedGC
  *                    TestVerifyJCStress
  *
  * @run main/othervm  -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions
  *                    -XX:+UseShenandoahGC -Xmx1g -Xms1g
- *                    -XX:+ShenandoahStoreCheck -XX:+ShenandoahVerify -XX:+VerifyObjectEquals -XX:+ShenandoahVerifyOptoBarriers
+ *                    -XX:+ShenandoahVerify -XX:+VerifyObjectEquals -XX:+ShenandoahVerifyOptoBarriers
  *                    -XX:ShenandoahGCHeuristics=adaptive
  *                    TestVerifyJCStress
  *
  * @run main/othervm  -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions
  *                    -XX:+UseShenandoahGC -Xmx1g -Xms1g
- *                    -XX:+ShenandoahStoreCheck -XX:+ShenandoahVerify -XX:+VerifyObjectEquals -XX:+ShenandoahVerifyOptoBarriers
+ *                    -XX:+ShenandoahVerify -XX:+VerifyObjectEquals -XX:+ShenandoahVerifyOptoBarriers
  *                    -XX:ShenandoahGCHeuristics=static
  *                    TestVerifyJCStress
  *
  * @run main/othervm  -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions
  *                    -XX:+UseShenandoahGC -Xmx1g -Xms1g
- *                    -XX:+ShenandoahStoreCheck -XX:+ShenandoahVerify -XX:+VerifyObjectEquals -XX:+ShenandoahVerifyOptoBarriers
+ *                    -XX:+ShenandoahVerify -XX:+VerifyObjectEquals -XX:+ShenandoahVerifyOptoBarriers
  *                    -XX:ShenandoahGCHeuristics=traversal
  *                    TestVerifyJCStress
  */
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/contention/TC04/tc04t001/tc04t001.cpp	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/contention/TC04/tc04t001/tc04t001.cpp	Tue Jul 02 12:03:49 2019 -0400
@@ -119,19 +119,10 @@
 
     /* check if event is for tested object */
     if (jni->IsSameObject(object_M, obj)) {
-        jvmtiMonitorUsage usageInfo;
-
         if (lockSyncLock(jvmti)) {
             enterEventsCount++;
             unlockSyncLock(jvmti);
         }
-
-        if (!NSK_JVMTI_VERIFY(jvmti->GetObjectMonitorUsage(obj, &usageInfo))) {
-            nsk_jvmti_setFailStatus();
-        } else if (usageInfo.owner != NULL) {
-            if (!NSK_JVMTI_VERIFY(jvmti->InterruptThread(usageInfo.owner)))
-                nsk_jvmti_setFailStatus();
-        }
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersFromPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Flow.Publisher;
+import java.util.stream.Stream;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersFromPublisher
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    public BodyPublishersFromPublisher() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        Stream<ByteBuffer> buffers =
+                Stream.generate(() -> S.bufferOfNRandomBytes(1024))
+                      .limit(nElements);
+        Publisher<ByteBuffer> pub = S.publisherOfStream(buffers);
+        return BodyPublishers.fromPublisher(pub);
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return BodyPublishers.fromPublisher(S.newErroredPublisher());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersNoBody.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Flow.Publisher;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersNoBody
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    public BodyPublishersNoBody() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        return BodyPublishers.noBody();
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return null;
+    }
+
+    @Override
+    public long maxElementsFromPublisher() {
+        return 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersOfByteArray.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Flow.Publisher;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersOfByteArray
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    private static final int ELEMENT_SIZE = 16 * 1024;
+
+    public BodyPublishersOfByteArray() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        byte[] b = S.arrayOfNRandomBytes(nElements * ELEMENT_SIZE);
+        return BodyPublishers.ofByteArray(b);
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return null;
+    }
+
+    @Override
+    public long maxElementsFromPublisher() {
+        return 21;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersOfByteArrays.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.concurrent.Flow.Publisher;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersOfByteArrays
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    private static final int ELEMENT_SIZE = 16 * 1024;
+
+    public BodyPublishersOfByteArrays() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        byte[] bytes = S.arrayOfNRandomBytes(ELEMENT_SIZE);
+        return BodyPublishers.ofByteArrays(
+                Collections.nCopies((int) nElements, bytes));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersOfFile.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Flow.Publisher;
+import java.util.concurrent.atomic.AtomicLong;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersOfFile
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    private static final int ELEMENT_SIZE = 16 * 1024;
+    private static final AtomicLong UNIQUE_NUMBERS = new AtomicLong();
+
+    public BodyPublishersOfFile() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        try {
+            Path f = createFile(nElements * ELEMENT_SIZE);
+            return BodyPublishers.ofFile(f);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private static Path createFile(long nBytes) throws IOException {
+        String name = "f" + UNIQUE_NUMBERS.getAndIncrement();
+        Path f = Files.createFile(Path.of(name));
+        return Files.write(f, S.arrayOfNRandomBytes(nBytes));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return null;
+    }
+
+    @Override
+    public long maxElementsFromPublisher() {
+        return 21;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersOfInputStream.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.io.InputStream;
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Flow.Publisher;
+import java.util.function.Supplier;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersOfInputStream
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    public BodyPublishersOfInputStream() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        Supplier<InputStream> s = () -> S.inputStreamOfNReads((int) nElements);
+        return BodyPublishers.ofInputStream(s);
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodyPublishersOfSubByteArray.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.ByteBuffer;
+import java.util.concurrent.Flow.Publisher;
+
+/* See TckDriver.java for more information */
+public class BodyPublishersOfSubByteArray
+        extends FlowPublisherVerification<ByteBuffer> {
+
+    private static final int ELEMENT_SIZE = 16 * 1024;
+
+    public BodyPublishersOfSubByteArray() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFlowPublisher(long nElements) {
+        int prefixLen = S.randomIntUpTo(13);
+        int postfixLen = S.randomIntUpTo(17);
+        byte[] b = S.arrayOfNRandomBytes(nElements * ELEMENT_SIZE);
+        byte[] contents = new byte[prefixLen + b.length + postfixLen];
+        System.arraycopy(b, 0, contents, prefixLen, b.length);
+        return BodyPublishers.ofByteArray(contents, prefixLen, b.length);
+    }
+
+    @Override
+    public Publisher<ByteBuffer> createFailedFlowPublisher() {
+        return null;
+    }
+
+    @Override
+    public long maxElementsFromPublisher() {
+        return 21;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersBuffering.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersBuffering
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersBuffering() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.buffering(BodySubscribers.discarding(),
+                                         S.randomIntUpTo(1024) + 1);
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersDiscarding.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersDiscarding
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersDiscarding() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.discarding();
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersFromLineSubscriber.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersFromLineSubscriber
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersFromLineSubscriber() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.fromLineSubscriber(
+                S.nonCompliantSubscriber());
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.scatterBuffer(
+                S.bufferOfNRandomASCIIBytes(element % 17));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersFromSubscriber.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersFromSubscriber
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersFromSubscriber() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        Subscriber<List<ByteBuffer>> sub = S.nonCompliantSubscriber();
+        return BodySubscribers.fromSubscriber(sub);
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.scatterBuffer(
+                S.bufferOfNRandomASCIIBytes(element % 17));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersMapping.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersMapping
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersMapping() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.mapping(BodySubscribers.ofByteArray(),
+                                       bytes -> bytes.length);
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfByteArray.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfByteArray
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfByteArray() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofByteArray();
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfByteArrayConsumer.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfByteArrayConsumer
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfByteArrayConsumer() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofByteArrayConsumer(bytes -> { });
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfFile.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfFile
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfFile() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofFile(Path.of("f1.bin"));
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfInputStream.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfInputStream
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfInputStream() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofInputStream();
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfLines.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfLines
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfLines() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofLines(StandardCharsets.UTF_8);
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.scatterBuffer(
+                S.bufferOfNRandomASCIIBytes(element % 17));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscriber;
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Flow.Publisher;
+import java.util.concurrent.Flow.Subscriber;
+import java.util.concurrent.Flow.Subscription;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfPublisher
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfPublisher() {
+        super(new TestEnvironment(450L));
+    }
+
+    /* The reason for overriding this method is that BodySubscribers.ofPublisher
+       is somewhat tricky. It is not an independent Subscriber, but rather
+       an adaptor from Subscriber to Publisher. Until the Subscriber that
+       subscribed to that resulting Publisher requests anything, nothing
+       happens. */
+    @Override
+    public void triggerFlowRequest(
+            Subscriber<? super List<ByteBuffer>> subscriber)
+    {
+        BodySubscriber<Publisher<List<ByteBuffer>>> sub =
+                (BodySubscriber<Publisher<List<ByteBuffer>>>) subscriber;
+        CompletionStage<Publisher<List<ByteBuffer>>> body = sub.getBody();
+        Publisher<List<ByteBuffer>> pub = body.toCompletableFuture().join();
+        pub.subscribe(new Subscriber<>() {
+
+            @Override
+            public void onSubscribe(Subscription subscription) {
+                subscription.request(Integer.MAX_VALUE);
+            }
+
+            @Override public void onNext(List<ByteBuffer> item) { }
+            @Override public void onError(Throwable throwable) { }
+            @Override public void onComplete() { }
+        });
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofPublisher();
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfPublisher1.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscriber;
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Flow.Publisher;
+import java.util.concurrent.Flow.Subscriber;
+import java.util.concurrent.Flow.Subscription;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfPublisher1
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfPublisher1() {
+        super(new TestEnvironment(450L));
+    }
+
+    /* The reason for overriding this method is that BodySubscribers.ofPublisher
+       is somewhat tricky. It is not an independent Subscriber, but rather
+       an adaptor from Subscriber to Publisher. Until the Subscriber that
+       subscribed to that resulting Publisher requests anything, nothing
+       happens. */
+    @Override
+    public void triggerFlowRequest(
+            Subscriber<? super List<ByteBuffer>> subscriber)
+    {
+        BodySubscriber<Publisher<List<ByteBuffer>>> sub =
+                (BodySubscriber<Publisher<List<ByteBuffer>>>) subscriber;
+        CompletionStage<Publisher<List<ByteBuffer>>> body = sub.getBody();
+        Publisher<List<ByteBuffer>> pub = body.toCompletableFuture().join();
+        pub.subscribe(new Subscriber<>() {
+
+            Subscription sub;
+
+            @Override
+            public void onSubscribe(Subscription subscription) {
+                (sub = subscription).request(1);
+            }
+
+            @Override public void onNext(List<ByteBuffer> item) {
+                sub.request(1);
+            }
+
+            @Override public void onError(Throwable throwable) { }
+            @Override public void onComplete() { }
+        });
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofPublisher();
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfPublisherPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.net.http.HttpResponse.BodySubscriber;
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Publisher;
+import java.util.stream.Stream;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfPublisherPublisher
+        extends FlowPublisherVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfPublisherPublisher() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<List<ByteBuffer>> createFlowPublisher(long nElements) {
+        BodySubscriber<Publisher<List<ByteBuffer>>> sub =
+                BodySubscribers.ofPublisher();
+        Stream<List<ByteBuffer>> buffers =
+                Stream.generate(() -> S.listOfBuffersFromBufferOfNBytes(1024))
+                      .limit(nElements);
+        Publisher<List<ByteBuffer>> pub = S.publisherOfStream(buffers);
+        pub.subscribe(sub);
+        return sub.getBody().toCompletableFuture().join();
+    }
+
+    @Override
+    public Publisher<List<ByteBuffer>> createFailedFlowPublisher() {
+        BodySubscriber<Publisher<List<ByteBuffer>>> sub =
+                BodySubscribers.ofPublisher();
+        Publisher<List<ByteBuffer>> pub = S.newErroredPublisher();
+        pub.subscribe(sub);
+        return sub.getBody().toCompletableFuture().join();
+    }
+
+    @Override
+    public long maxElementsFromPublisher() {
+        return 21;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersOfString.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersOfString
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersOfString() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        return BodySubscribers.ofString(StandardCharsets.UTF_8);
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.scatterBuffer(
+                S.bufferOfNRandomASCIIBytes(element % 17));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/BodySubscribersReplacing.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowSubscriberBlackboxVerification;
+
+import java.net.http.HttpResponse.BodySubscribers;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.Flow.Subscriber;
+
+/* See TckDriver.java for more information */
+public class BodySubscribersReplacing
+        extends FlowSubscriberBlackboxVerification<List<ByteBuffer>> {
+
+    public BodySubscribersReplacing() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Subscriber<List<ByteBuffer>> createFlowSubscriber() {
+        /* it doesn't matter what we are replacing with */
+        return BodySubscribers.replacing(Boolean.TRUE);
+    }
+
+    @Override
+    public List<ByteBuffer> createElement(int element) {
+        return S.listOfBuffersFromBufferOfNBytes(element % 17);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/S.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.concurrent.Flow.Publisher;
+import java.util.concurrent.Flow.Subscriber;
+import java.util.concurrent.Flow.Subscription;
+import java.util.stream.Stream;
+
+/*
+ * S for Support.
+ *
+ * Auxiliary methods for tests that check conformance with reactive streams
+ * specification.
+ *
+ * Short name is for the sake of convenience calling this class' static methods.
+ * It could've been called Support or TckSupport, but then we would need to
+ * place this class in its own package so as to use "import static".
+ */
+public class S {
+
+    private static final Random RANDOM = new SecureRandom();
+
+    private S() { }
+
+    public static List<ByteBuffer> listOfBuffersFromBufferOfNBytes(int nBytes) {
+        return scatterBuffer(bufferOfNRandomBytes(nBytes));
+    }
+
+    /*
+     * Spreads the remaining contents of the given byte buffer across a number
+     * of buffers put into a list.
+     */
+    public static List<ByteBuffer> scatterBuffer(ByteBuffer src) {
+        List<ByteBuffer> buffers = new ArrayList<>();
+        while (src.hasRemaining()) {
+            // We do not allow empty buffers ~~~~~~~~~~~~~~~~v
+            int capacity = RANDOM.nextInt(src.remaining()) + 1;
+            ByteBuffer b = ByteBuffer.allocate(capacity);
+            for (int i = 0; i < capacity; i++) {
+                b.put(src.get());
+            }
+            b.flip();
+            buffers.add(b);
+        }
+        return List.copyOf(buffers);
+    }
+
+    public static ByteBuffer bufferOfNRandomBytes(int capacity) {
+        return ByteBuffer.wrap(arrayOfNRandomBytes(capacity));
+    }
+
+    public static byte[] arrayOfNRandomBytes(int nBytes) {
+        byte[] contents = new byte[nBytes];
+        RANDOM.nextBytes(contents);
+        return contents;
+    }
+
+    public static InputStream inputStreamOfNReads(long n) {
+        return new NReadsInputStream(n);
+    }
+
+    /*
+     * Convenience method for testing publishers.
+     */
+    public static byte[] arrayOfNRandomBytes(long nBytes) {
+        return arrayOfNRandomBytes((int) nBytes);
+    }
+
+    public static ByteBuffer bufferOfNRandomASCIIBytes(int capacity) {
+        String alphaNumeric = "abcdefghijklmnopqrstuvwxyz1234567890";
+        StringBuilder builder = new StringBuilder(capacity);
+        for (int i = 0; i < capacity; i++) {
+            int idx = RANDOM.nextInt(alphaNumeric.length());
+            builder.append(alphaNumeric.charAt(idx));
+        }
+        return ByteBuffer.wrap(builder.toString().getBytes(
+                StandardCharsets.US_ASCII));
+    }
+
+    /*
+     * Returns a simple non-compliant Subscriber.
+     *
+     * This Subscriber is useful for testing our adaptors and wrappers, to make
+     * sure they do not delegate RS compliance to the underlying (and foreign to
+     * java.net.http codebase) Subscribers, but rather comply themselves.
+     *
+     * Here's an example:
+     *
+     *     public void onSubscribe(Subscription s) {
+     *         delegate.onSubscribe(s);
+     *     }
+     *
+     * The snippet above cannot be considered a good implementation of a
+     * Subscriber if `delegate` is an unknown Subscriber. In this case the
+     * implementation should independently check all the rules from the RS spec
+     * related to subscribers.
+     */
+    public static <T> Subscriber<T> nonCompliantSubscriber() {
+        return new Subscriber<>() {
+
+            @Override
+            public void onSubscribe(Subscription subscription) {
+                subscription.request(Long.MAX_VALUE);
+            }
+
+            @Override
+            public void onNext(T item) { }
+
+            @Override
+            public void onError(Throwable throwable) { }
+
+            @Override
+            public void onComplete() { }
+        };
+    }
+
+    public static int randomIntUpTo(int bound) {
+        return RANDOM.nextInt(bound);
+    }
+
+    /*
+     * Signals an error to its subscribers immediately after subscription.
+     */
+    public static <T> Publisher<T> newErroredPublisher() {
+        return subscriber -> {
+            subscriber.onSubscribe(new Subscription() {
+                @Override
+                public void request(long n) { }
+
+                @Override
+                public void cancel() { }
+            });
+            subscriber.onError(new IOException());
+        };
+    }
+
+    /*
+     * Publishes the elements obtained from the stream and signals completion.
+     * Can be cancelled, but cannot signal an error.
+     *
+     * This trivial ad-hoc implementation of Publisher was created so as to
+     * publish lists of byte buffers. We can publish ByteBuffer, but we can't
+     * seem to publish List<ByteBuffer> since there's no readily available
+     * publisher of those, nor there's a simple adaptor.
+     */
+    public static <T> Publisher<T> publisherOfStream(Stream<? extends T> stream)
+    {
+        if (stream == null) {
+            throw new NullPointerException();
+        }
+        return new Publisher<T>() {
+            @Override
+            public void subscribe(Subscriber<? super T> subscriber) {
+                if (subscriber == null) {
+                    throw new NullPointerException();
+                }
+                Subscription subscription = new Subscription() {
+
+                    boolean inOnNext; // recursion control
+                    volatile boolean cancelled;
+                    long demand;
+                    final Iterator<? extends T> supply = stream.iterator();
+
+                    @Override
+                    public void request(long n) {
+                        demand = demand + n < 0 ? Long.MAX_VALUE : demand + n;
+                        if (inOnNext) {
+                            return;
+                        }
+                        if (cancelled)
+                            return;
+                        if (n <= 0) {
+                            cancelled = true;
+                            subscriber.onError(new IllegalArgumentException(
+                                    "non-positive subscription request"));
+                            return;
+                        }
+                        while (supply.hasNext() && demand > 0 && !cancelled) {
+                            demand--;
+                            inOnNext = true;
+                            try {
+                                T item = supply.next();
+                                subscriber.onNext(item);
+                            } finally {
+                                inOnNext = false;
+                            }
+                        }
+                        if (!supply.hasNext()) {
+                            cancelled = true;
+                            subscriber.onComplete();
+                        }
+                    }
+
+                    @Override
+                    public void cancel() {
+                        cancelled = true;
+                    }
+                };
+                subscriber.onSubscribe(subscription);
+            }
+        };
+    }
+
+    static final class NReadsInputStream extends InputStream {
+
+        private static final int EOF = -1;
+        private long readsLeft;
+
+        NReadsInputStream(long n) {
+            if (n < 0) {
+                throw new IllegalArgumentException(String.valueOf(n));
+            }
+            this.readsLeft = n;
+        }
+
+        @Override
+        public int read() {
+            if (readsLeft == 0L) {
+                return EOF;
+            }
+            readsLeft--;
+            return S.randomIntUpTo(256);
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) {
+            Objects.checkFromIndexSize(off, len, b.length);
+            // Must return 0 if len == 0,
+            // even if there are no more reads left
+            if (len == 0) {
+                return 0;
+            }
+            if (readsLeft == 0L) {
+                return EOF;
+            }
+            readsLeft--;
+            // At least one byte MUST be read, but we can read
+            // less than `len` bytes
+            int r = RANDOM.nextInt(len) + 1;
+            for (int i = 0; i < r; i++) {
+                b[i] = (byte) randomIntUpTo(256);
+            }
+            return r;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/SPublisherOfStream.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.FlowPublisherVerification;
+
+import java.util.concurrent.Flow.Publisher;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+
+/* See TckDriver.java for more information */
+public class SPublisherOfStream
+        extends FlowPublisherVerification<Long> {
+
+    public SPublisherOfStream() {
+        super(new TestEnvironment(450L));
+    }
+
+    @Override
+    public Publisher<Long> createFlowPublisher(long nElements) {
+        Stream<Long> s = LongStream.range(0, nElements).boxed();
+        return S.publisherOfStream(s);
+    }
+
+    @Override
+    public Publisher<Long> createFailedFlowPublisher() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/STest.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class STest {
+
+    @DataProvider(name = "bufferSizes")
+    public static Object[][] bufferSizes() {
+        return new Object[][]{
+                { 1},
+                { 2},
+                { 3},
+                { 4},
+                {16},
+                {17},
+        };
+    }
+
+    @DataProvider
+    public static Object[][] inputStream() {
+        return new Object[][] {
+                {  0,   1},
+                {  1,   2},
+                {  1,   3},
+                {  1,   4},
+                {  2,   1},
+                {  2,   2},
+                {  2,   3},
+                {  2,   4},
+                {  2,  13},
+                {  3,   1},
+                {  3,   2},
+                {  3,   3},
+                {  3,   4},
+                {  3,  17},
+                {  4,   1},
+                {  4,   2},
+                {  4,   3},
+                {  4,   4},
+                {  4,   5},
+                { 13,   1},
+                { 13,   2},
+                { 13,  13},
+                { 16,  18},
+                { 17,   2},
+                {255,   1},
+                {256, 255},
+                {257, 267},
+        };
+    }
+
+    @Test
+    public void testScatter0() {
+        List<ByteBuffer> buffers = S.scatterBuffer(
+                ByteBuffer.allocate(0));
+        assertEquals(buffers.size(), 0);
+    }
+
+    @Test(dataProvider = "bufferSizes")
+    public void testScatterN(int n) {
+        final ByteBuffer src = S.bufferOfNRandomBytes(n);
+        final int srcLength = src.remaining();
+        ByteBuffer copy = ByteBuffer.wrap(Arrays.copyOf(src.array(),
+                                                        src.array().length));
+        List<ByteBuffer> buffers = S.scatterBuffer(src);
+        int m = 0;
+        for (ByteBuffer b : buffers) {
+            m += b.remaining();
+            while (b.hasRemaining() & copy.hasRemaining()) {
+                assertEquals(b.get(), copy.get());
+            }
+        }
+        assertEquals(m, srcLength);
+    }
+
+    @Test(dataProvider = "inputStream")
+    public void testInputStreamOfNReads(int n, int capacity) throws IOException {
+        InputStream s = S.inputStreamOfNReads(n);
+        int count = 0;
+        byte[] b = new byte[capacity];
+        while (s.read(b) != -1) {
+            count++;
+        }
+        assertEquals(count, n);
+        assertTrue(s.read() == -1);
+        assertTrue(s.read(b) == -1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck-tests/TckDriver.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8226602
+ * @summary Tests convenience reactive primitives with RS TCK
+ *
+ * @library ../reactivestreams-tck
+ * @build S
+ *
+ * @compile -encoding UTF-8 SPublisherOfStream.java
+ *
+ * @compile -encoding UTF-8 BodyPublishersFromPublisher.java
+ * @compile -encoding UTF-8 BodyPublishersNoBody.java
+ * @compile -encoding UTF-8 BodyPublishersOfByteArray.java
+ * @compile -encoding UTF-8 BodyPublishersOfByteArrays.java
+ * @compile -encoding UTF-8 BodyPublishersOfFile.java
+ * @compile -encoding UTF-8 BodyPublishersOfInputStream.java
+ * @compile -encoding UTF-8 BodyPublishersOfSubByteArray.java
+ *
+ * @compile -encoding UTF-8 BodySubscribersBuffering.java
+ * @compile -encoding UTF-8 BodySubscribersDiscarding.java
+ * @compile -encoding UTF-8 BodySubscribersFromLineSubscriber.java
+ * @compile -encoding UTF-8 BodySubscribersFromSubscriber.java
+ * @compile -encoding UTF-8 BodySubscribersMapping.java
+ * @compile -encoding UTF-8 BodySubscribersOfByteArray.java
+ * @compile -encoding UTF-8 BodySubscribersOfByteArrayConsumer.java
+ * @compile -encoding UTF-8 BodySubscribersOfFile.java
+ * @compile -encoding UTF-8 BodySubscribersOfInputStream.java
+ * @compile -encoding UTF-8 BodySubscribersOfLines.java
+ * @compile -encoding UTF-8 BodySubscribersOfPublisher.java
+ * @compile -encoding UTF-8 BodySubscribersOfPublisher1.java
+ * @compile -encoding UTF-8 BodySubscribersOfPublisherPublisher.java
+ * @compile -encoding UTF-8 BodySubscribersOfString.java
+ * @compile -encoding UTF-8 BodySubscribersReplacing.java
+ *
+ * @run testng/othervm STest
+ * @run testng/othervm SPublisherOfStream
+ *
+ * @run testng/othervm BodyPublishersFromPublisher
+ * @run testng/othervm BodyPublishersNoBody
+ * @run testng/othervm BodyPublishersOfByteArray
+ * @run testng/othervm BodyPublishersOfByteArrays
+ * @run testng/othervm BodyPublishersOfFile
+ * @run testng/othervm BodyPublishersOfInputStream
+ * @run testng/othervm BodyPublishersOfSubByteArray
+ *
+ * @run testng/othervm BodySubscribersBuffering
+ * @run testng/othervm BodySubscribersDiscarding
+ * @run testng/othervm BodySubscribersFromLineSubscriber
+ * @run testng/othervm BodySubscribersFromSubscriber
+ * @run testng/othervm BodySubscribersMapping
+ * @run testng/othervm BodySubscribersOfByteArray
+ * @run testng/othervm BodySubscribersOfByteArrayConsumer
+ * @run testng/othervm BodySubscribersOfFile
+ * @run testng/othervm BodySubscribersOfInputStream
+ * @run testng/othervm BodySubscribersOfLines
+ * @run testng/othervm BodySubscribersOfPublisher
+ * @run testng/othervm BodySubscribersOfPublisher1
+ * @run testng/othervm BodySubscribersOfPublisherPublisher
+ * @run testng/othervm BodySubscribersOfString
+ * @run testng/othervm BodySubscribersReplacing
+ *
+ * @key randomness
+ */
+public class TckDriver {
+   /*
+        #### General Information
+
+        1. This JTREG test aggregates multiple TestNG tests. This is because
+        these tests share a common library (reactivestreams-tck), and we don't
+        want this library to be compiled separately for each of those tests.
+
+        2. Tests that use RS TCK are compiled with the UTF-8 encoding. This is
+        performed for the sake of reactivestreams-tck. We don't want to patch
+        the TCK because of the extra merging work in the future, should we bring
+        update(s) from the RS repo.
+
+        #### Tests
+
+        1. The purpose of each test should be easily digestible. The name of the
+        test is derived from the very entity the test exercises. For example,
+
+            the BodyPublishersOfFile test exercises the BodyPublisher obtained
+            by calling BodyPublishers.ofFile(Path)
+
+            the BodySubscribersOfFile test exercises the BodySubscriber obtained
+            by calling BodySubscribers.ofFile(Path)
+
+        2. RS TCK requires PublisherVerification tests to produce publishers
+        capable of emitting a certain number of elements. In order to achieve
+        this, we use some knowledge of the internal workings of our publishers.
+        An example would be a chunk size a publisher uses to deliver a portion
+        of data. Without knowing that it is not possible to guarantee that the
+        publisher will emit a particular number of elements.
+
+        3. Typically our publishers cannot be created in a known failed state.
+        In this case the corresponding `createFailedFlowPublisher` method
+        returns `null`.
+
+        4. SubscriberBlackBoxVerification uses the `createElement(int element)`
+        method. Our implementations usually cap the amount of data created by
+        this method, because it's not known beforehand how big the `element`
+        value is. Hence, sometimes there's code like as follows:
+
+            @Override
+            public List<ByteBuffer> createElement(int element) {
+                return scatterBuffer(
+                        bufferOfNRandomASCIIBytes(element % 17));
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
+            }
+
+        5. The amount of testing RS TCK performs on a publisher seems to depend
+        on the number of elements this publisher reports it can emit. Sometimes
+        a code like the following can be seen in the tests:
+
+                @Override public long maxElementsFromPublisher() {
+                    return 21;
+                ~~~~~~~~~~~^
+                }
+
+        This magic number is a result of trial and error and seems to unlock
+        most of the tests. Reporting big values (e.g. Long.MAX_VALUE - 1) is
+        not an option for most of our publishers because they require to have
+        all the elements upfront.
+
+        6. It doesn't seem currently feasible to provide SubscriberWhiteboxVerification
+        tests as a) it's not clear how much better the coverage is and b) it's
+        significantly harder to code that.
+
+        #### S (Support)
+
+        Support utilities are being tested (STest) too.
+    */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/FlowAdapters.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams;
+
+import java.util.concurrent.Flow;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Bridge between Reactive Streams API and the Java 9 {@link java.util.concurrent.Flow} API.
+ */
+public final class FlowAdapters {
+    /** Utility class. */
+    private FlowAdapters() {
+        throw new IllegalStateException("No instances!");
+    }
+
+    /**
+     * Converts a Flow Publisher into a Reactive Streams Publisher.
+     * @param <T> the element type
+     * @param flowPublisher the source Flow Publisher to convert
+     * @return the equivalent Reactive Streams Publisher
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> org.reactivestreams.Publisher<T> toPublisher(
+            Flow.Publisher<? extends T> flowPublisher) {
+        requireNonNull(flowPublisher, "flowPublisher");
+        final org.reactivestreams.Publisher<T> publisher;
+        if (flowPublisher instanceof FlowPublisherFromReactive) {
+            publisher = (org.reactivestreams.Publisher<T>)(((FlowPublisherFromReactive<T>)flowPublisher).reactiveStreams);
+        } else if (flowPublisher instanceof org.reactivestreams.Publisher) {
+            publisher = (org.reactivestreams.Publisher<T>)flowPublisher;
+        } else {
+            publisher = new ReactivePublisherFromFlow<T>(flowPublisher);
+        }
+        return publisher;
+    }
+
+    /**
+     * Converts a Reactive Streams Publisher into a Flow Publisher.
+     * @param <T> the element type
+     * @param reactiveStreamsPublisher the source Reactive Streams Publisher to convert
+     * @return the equivalent Flow Publisher
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Flow.Publisher<T> toFlowPublisher(
+            org.reactivestreams.Publisher<? extends T> reactiveStreamsPublisher
+    ) {
+        requireNonNull(reactiveStreamsPublisher, "reactiveStreamsPublisher");
+        final Flow.Publisher<T> flowPublisher;
+        if (reactiveStreamsPublisher instanceof ReactivePublisherFromFlow) {
+            flowPublisher = (Flow.Publisher<T>)(((ReactivePublisherFromFlow<T>)reactiveStreamsPublisher).flow);
+        } else if (reactiveStreamsPublisher instanceof Flow.Publisher) {
+            flowPublisher = (Flow.Publisher<T>)reactiveStreamsPublisher;
+        } else {
+            flowPublisher = new FlowPublisherFromReactive<T>(reactiveStreamsPublisher);
+        }
+        return flowPublisher;
+    }
+
+    /**
+     * Converts a Flow Processor into a Reactive Streams Processor.
+     * @param <T> the input value type
+     * @param <U> the output value type
+     * @param flowProcessor the source Flow Processor to convert
+     * @return the equivalent Reactive Streams Processor
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, U> org.reactivestreams.Processor<T, U> toProcessor(
+            Flow.Processor<? super T, ? extends U> flowProcessor
+    ) {
+        requireNonNull(flowProcessor, "flowProcessor");
+        final org.reactivestreams.Processor<T, U> processor;
+        if (flowProcessor instanceof FlowToReactiveProcessor) {
+            processor = (org.reactivestreams.Processor<T, U>)(((FlowToReactiveProcessor<T, U>)flowProcessor).reactiveStreams);
+        } else if (flowProcessor instanceof org.reactivestreams.Processor) {
+            processor = (org.reactivestreams.Processor<T, U>)flowProcessor;
+        } else {
+            processor = new ReactiveToFlowProcessor<T, U>(flowProcessor);
+        }
+        return processor;
+    }
+
+    /**
+     * Converts a Reactive Streams Processor into a Flow Processor.
+     * @param <T> the input value type
+     * @param <U> the output value type
+     * @param reactiveStreamsProcessor the source Reactive Streams Processor to convert
+     * @return the equivalent Flow Processor
+     */
+    @SuppressWarnings("unchecked")
+    public static <T, U> Flow.Processor<T, U> toFlowProcessor(
+            org.reactivestreams.Processor<? super T, ? extends U> reactiveStreamsProcessor
+        ) {
+        requireNonNull(reactiveStreamsProcessor, "reactiveStreamsProcessor");
+        final Flow.Processor<T, U> flowProcessor;
+        if (reactiveStreamsProcessor instanceof ReactiveToFlowProcessor) {
+            flowProcessor = (Flow.Processor<T, U>)(((ReactiveToFlowProcessor<T, U>)reactiveStreamsProcessor).flow);
+        } else if (reactiveStreamsProcessor instanceof Flow.Processor) {
+            flowProcessor = (Flow.Processor<T, U>)reactiveStreamsProcessor;
+        } else {
+            flowProcessor = new FlowToReactiveProcessor<T, U>(reactiveStreamsProcessor);
+        }
+        return flowProcessor;
+    }
+
+    /**
+     * Converts a Reactive Streams Subscriber into a Flow Subscriber.
+     * @param <T> the input and output value type
+     * @param reactiveStreamsSubscriber the Reactive Streams Subscriber instance to convert
+     * @return the equivalent Flow Subscriber
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Flow.Subscriber<T> toFlowSubscriber(org.reactivestreams.Subscriber<T> reactiveStreamsSubscriber) {
+        requireNonNull(reactiveStreamsSubscriber, "reactiveStreamsSubscriber");
+        final Flow.Subscriber<T> flowSubscriber;
+        if (reactiveStreamsSubscriber instanceof ReactiveToFlowSubscriber) {
+            flowSubscriber = (Flow.Subscriber<T>)((ReactiveToFlowSubscriber<T>)reactiveStreamsSubscriber).flow;
+        } else if (reactiveStreamsSubscriber instanceof Flow.Subscriber) {
+            flowSubscriber = (Flow.Subscriber<T>)reactiveStreamsSubscriber;
+        } else {
+            flowSubscriber = new FlowToReactiveSubscriber<T>(reactiveStreamsSubscriber);
+        }
+        return flowSubscriber;
+    }
+
+    /**
+     * Converts a Flow Subscriber into a Reactive Streams Subscriber.
+     * @param <T> the input and output value type
+     * @param flowSubscriber the Flow Subscriber instance to convert
+     * @return the equivalent Reactive Streams Subscriber
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> org.reactivestreams.Subscriber<T> toSubscriber(Flow.Subscriber<T> flowSubscriber) {
+        requireNonNull(flowSubscriber, "flowSubscriber");
+        final org.reactivestreams.Subscriber<T> subscriber;
+        if (flowSubscriber instanceof FlowToReactiveSubscriber) {
+            subscriber = (org.reactivestreams.Subscriber<T>)((FlowToReactiveSubscriber<T>)flowSubscriber).reactiveStreams;
+        } else if (flowSubscriber instanceof org.reactivestreams.Subscriber) {
+            subscriber = (org.reactivestreams.Subscriber<T>)flowSubscriber;
+        } else {
+            subscriber = new ReactiveToFlowSubscriber<T>(flowSubscriber);
+        }
+        return subscriber;
+    }
+
+    /**
+     * Wraps a Reactive Streams Subscription and converts the calls to a Flow Subscription.
+     */
+    static final class FlowToReactiveSubscription implements Flow.Subscription {
+        final org.reactivestreams.Subscription reactiveStreams;
+
+        public FlowToReactiveSubscription(org.reactivestreams.Subscription reactive) {
+            this.reactiveStreams = reactive;
+        }
+
+        @Override
+        public void request(long n) {
+            reactiveStreams.request(n);
+        }
+
+        @Override
+        public void cancel() {
+            reactiveStreams.cancel();
+        }
+
+    }
+
+    /**
+     * Wraps a Flow Subscription and converts the calls to a Reactive Streams Subscription.
+     */
+    static final class ReactiveToFlowSubscription implements org.reactivestreams.Subscription {
+        final Flow.Subscription flow;
+
+        public ReactiveToFlowSubscription(Flow.Subscription flow) {
+            this.flow = flow;
+        }
+
+        @Override
+        public void request(long n) {
+            flow.request(n);
+        }
+
+        @Override
+        public void cancel() {
+            flow.cancel();
+        }
+
+
+    }
+
+    /**
+     * Wraps a Reactive Streams Subscriber and forwards methods of the Flow Subscriber to it.
+     * @param <T> the element type
+     */
+    static final class FlowToReactiveSubscriber<T> implements Flow.Subscriber<T> {
+        final org.reactivestreams.Subscriber<? super T> reactiveStreams;
+
+        public FlowToReactiveSubscriber(org.reactivestreams.Subscriber<? super T> reactive) {
+            this.reactiveStreams = reactive;
+        }
+
+        @Override
+        public void onSubscribe(Flow.Subscription subscription) {
+            reactiveStreams.onSubscribe((subscription == null) ? null : new ReactiveToFlowSubscription(subscription));
+        }
+
+        @Override
+        public void onNext(T item) {
+            reactiveStreams.onNext(item);
+        }
+
+        @Override
+        public void onError(Throwable throwable) {
+            reactiveStreams.onError(throwable);
+        }
+
+        @Override
+        public void onComplete() {
+            reactiveStreams.onComplete();
+        }
+
+    }
+
+    /**
+     * Wraps a Flow Subscriber and forwards methods of the Reactive Streams Subscriber to it.
+     * @param <T> the element type
+     */
+    static final class ReactiveToFlowSubscriber<T> implements org.reactivestreams.Subscriber<T> {
+        final Flow.Subscriber<? super T> flow;
+
+        public ReactiveToFlowSubscriber(Flow.Subscriber<? super T> flow) {
+            this.flow = flow;
+        }
+
+        @Override
+        public void onSubscribe(org.reactivestreams.Subscription subscription) {
+            flow.onSubscribe((subscription == null) ? null : new FlowToReactiveSubscription(subscription));
+        }
+
+        @Override
+        public void onNext(T item) {
+            flow.onNext(item);
+        }
+
+        @Override
+        public void onError(Throwable throwable) {
+            flow.onError(throwable);
+        }
+
+        @Override
+        public void onComplete() {
+            flow.onComplete();
+        }
+
+    }
+
+    /**
+     * Wraps a Flow Processor and forwards methods of the Reactive Streams Processor to it.
+     * @param <T> the input type
+     * @param <U> the output type
+     */
+    static final class ReactiveToFlowProcessor<T, U> implements org.reactivestreams.Processor<T, U> {
+        final Flow.Processor<? super T, ? extends U> flow;
+
+        public ReactiveToFlowProcessor(Flow.Processor<? super T, ? extends U> flow) {
+            this.flow = flow;
+        }
+
+        @Override
+        public void onSubscribe(org.reactivestreams.Subscription subscription) {
+            flow.onSubscribe((subscription == null) ? null : new FlowToReactiveSubscription(subscription));
+        }
+
+        @Override
+        public void onNext(T t) {
+            flow.onNext(t);
+        }
+
+        @Override
+        public void onError(Throwable t) {
+            flow.onError(t);
+        }
+
+        @Override
+        public void onComplete() {
+            flow.onComplete();
+        }
+
+        @Override
+        public void subscribe(org.reactivestreams.Subscriber<? super U> s) {
+            flow.subscribe((s == null) ? null : new FlowToReactiveSubscriber<U>(s));
+        }
+    }
+
+    /**
+     * Wraps a Reactive Streams Processor and forwards methods of the Flow Processor to it.
+     * @param <T> the input type
+     * @param <U> the output type
+     */
+    static final class FlowToReactiveProcessor<T, U> implements Flow.Processor<T, U> {
+        final org.reactivestreams.Processor<? super T, ? extends U> reactiveStreams;
+
+        public FlowToReactiveProcessor(org.reactivestreams.Processor<? super T, ? extends U> reactive) {
+            this.reactiveStreams = reactive;
+        }
+
+        @Override
+        public void onSubscribe(Flow.Subscription subscription) {
+            reactiveStreams.onSubscribe((subscription == null) ? null : new ReactiveToFlowSubscription(subscription));
+        }
+
+        @Override
+        public void onNext(T t) {
+            reactiveStreams.onNext(t);
+        }
+
+        @Override
+        public void onError(Throwable t) {
+            reactiveStreams.onError(t);
+        }
+
+        @Override
+        public void onComplete() {
+            reactiveStreams.onComplete();
+        }
+
+        @Override
+        public void subscribe(Flow.Subscriber<? super U> s) {
+            reactiveStreams.subscribe((s == null) ? null : new ReactiveToFlowSubscriber<U>(s));
+        }
+    }
+
+    /**
+     * Reactive Streams Publisher that wraps a Flow Publisher.
+     * @param <T> the element type
+     */
+    static final class ReactivePublisherFromFlow<T> implements org.reactivestreams.Publisher<T> {
+        final Flow.Publisher<? extends T> flow;
+
+        public ReactivePublisherFromFlow(Flow.Publisher<? extends T> flowPublisher) {
+            this.flow = flowPublisher;
+        }
+
+        @Override
+        public void subscribe(org.reactivestreams.Subscriber<? super T> reactive) {
+            flow.subscribe((reactive == null) ? null : new FlowToReactiveSubscriber<T>(reactive));
+        }
+    }
+
+    /**
+     * Flow Publisher that wraps a Reactive Streams Publisher.
+     * @param <T> the element type
+     */
+    static final class FlowPublisherFromReactive<T> implements Flow.Publisher<T> {
+
+        final org.reactivestreams.Publisher<? extends T> reactiveStreams;
+
+        public FlowPublisherFromReactive(org.reactivestreams.Publisher<? extends T> reactivePublisher) {
+            this.reactiveStreams = reactivePublisher;
+        }
+
+        @Override
+        public void subscribe(Flow.Subscriber<? super T> flow) {
+            reactiveStreams.subscribe((flow == null) ? null : new ReactiveToFlowSubscriber<T>(flow));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/Processor.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams;
+
+/**
+ * A Processor represents a processing stage—which is both a {@link Subscriber}
+ * and a {@link Publisher} and obeys the contracts of both.
+ *
+ * @param <T> the type of element signaled to the {@link Subscriber}
+ * @param <R> the type of element signaled by the {@link Publisher}
+ */
+public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/Publisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams;
+
+/**
+ * A {@link Publisher} is a provider of a potentially unbounded number of sequenced elements, publishing them according to
+ * the demand received from its {@link Subscriber}(s).
+ * <p>
+ * A {@link Publisher} can serve multiple {@link Subscriber}s subscribed {@link #subscribe(Subscriber)} dynamically
+ * at various points in time.
+ *
+ * @param <T> the type of element signaled.
+ */
+public interface Publisher<T> {
+
+    /**
+     * Request {@link Publisher} to start streaming data.
+     * <p>
+     * This is a "factory method" and can be called multiple times, each time starting a new {@link Subscription}.
+     * <p>
+     * Each {@link Subscription} will work for only a single {@link Subscriber}.
+     * <p>
+     * A {@link Subscriber} should only subscribe once to a single {@link Publisher}.
+     * <p>
+     * If the {@link Publisher} rejects the subscription attempt or otherwise fails it will
+     * signal the error via {@link Subscriber#onError}.
+     *
+     * @param s the {@link Subscriber} that will consume signals from this {@link Publisher}
+     */
+    public void subscribe(Subscriber<? super T> s);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/Subscriber.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams;
+
+/**
+ * Will receive call to {@link #onSubscribe(Subscription)} once after passing an instance of {@link Subscriber} to {@link Publisher#subscribe(Subscriber)}.
+ * <p>
+ * No further notifications will be received until {@link Subscription#request(long)} is called.
+ * <p>
+ * After signaling demand:
+ * <ul>
+ * <li>One or more invocations of {@link #onNext(Object)} up to the maximum number defined by {@link Subscription#request(long)}</li>
+ * <li>Single invocation of {@link #onError(Throwable)} or {@link Subscriber#onComplete()} which signals a terminal state after which no further events will be sent.
+ * </ul>
+ * <p>
+ * Demand can be signaled via {@link Subscription#request(long)} whenever the {@link Subscriber} instance is capable of handling more.
+ *
+ * @param <T> the type of element signaled.
+ */
+public interface Subscriber<T> {
+    /**
+     * Invoked after calling {@link Publisher#subscribe(Subscriber)}.
+     * <p>
+     * No data will start flowing until {@link Subscription#request(long)} is invoked.
+     * <p>
+     * It is the responsibility of this {@link Subscriber} instance to call {@link Subscription#request(long)} whenever more data is wanted.
+     * <p>
+     * The {@link Publisher} will send notifications only in response to {@link Subscription#request(long)}.
+     *
+     * @param s
+     *            {@link Subscription} that allows requesting data via {@link Subscription#request(long)}
+     */
+    public void onSubscribe(Subscription s);
+
+    /**
+     * Data notification sent by the {@link Publisher} in response to requests to {@link Subscription#request(long)}.
+     *
+     * @param t the element signaled
+     */
+    public void onNext(T t);
+
+    /**
+     * Failed terminal state.
+     * <p>
+     * No further events will be sent even if {@link Subscription#request(long)} is invoked again.
+     *
+     * @param t the throwable signaled
+     */
+    public void onError(Throwable t);
+
+    /**
+     * Successful terminal state.
+     * <p>
+     * No further events will be sent even if {@link Subscription#request(long)} is invoked again.
+     */
+    public void onComplete();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/Subscription.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams;
+
+/**
+ * A {@link Subscription} represents a one-to-one lifecycle of a {@link Subscriber} subscribing to a {@link Publisher}.
+ * <p>
+ * It can only be used once by a single {@link Subscriber}.
+ * <p>
+ * It is used to both signal desire for data and cancel demand (and allow resource cleanup).
+ *
+ */
+public interface Subscription {
+    /**
+     * No events will be sent by a {@link Publisher} until demand is signaled via this method.
+     * <p>
+     *  It can be called however often and whenever needed—but if the outstanding cumulative demand ever becomes Long.MAX_VALUE or more,
+     *  it may be treated by the {@link Publisher} as "effectively unbounded".
+     * <p>
+     * Whatever has been requested can be sent by the {@link Publisher} so only signal demand for what can be safely handled.
+     * <p>
+     * A {@link Publisher} can send less than is requested if the stream ends but
+     * then must emit either {@link Subscriber#onError(Throwable)} or {@link Subscriber#onComplete()}.
+     *
+     * @param n the strictly positive number of elements to requests to the upstream {@link Publisher}
+     */
+    public void request(long n);
+
+    /**
+     * Request the {@link Publisher} to stop sending data and clean up resources.
+     * <p>
+     * Data may still be sent to meet previously signalled demand after calling cancel.
+     */
+    public void cancel();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/example/unicast/AsyncIterablePublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.example.unicast;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+
+import java.util.Iterator;
+import java.util.Collections;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * 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.
+ */
+public class AsyncIterablePublisher<T> implements Publisher<T> {
+  private final static int DEFAULT_BATCHSIZE = 1024;
+
+  private final Iterable<T> elements; // This is our data source / generator
+  private final Executor executor; // This is our thread pool, which will make sure that our Publisher runs asynchronously to its Subscribers
+  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
+
+  public AsyncIterablePublisher(final Iterable<T> elements, final Executor executor) {
+    this(elements, DEFAULT_BATCHSIZE, executor);
+  }
+
+  public AsyncIterablePublisher(final Iterable<T> elements, final int batchSize, final Executor executor) {
+    if (elements == null) throw null;
+    if (executor == null) throw null;
+    if (batchSize < 1) throw new IllegalArgumentException("batchSize must be greater than zero!");
+    this.elements = elements;
+    this.executor = executor;
+    this.batchSize = batchSize;
+  }
+
+  @Override
+  public void subscribe(final Subscriber<? super T> s) {
+    // As per rule 1.11, we have decided to support multiple subscribers in a unicast configuration
+    // for this `Publisher` implementation.
+    // As per 2.13, this method must return normally (i.e. not throw)
+    new SubscriptionImpl(s).init();
+  }
+
+  // These represent the protocol of the `AsyncIterablePublishers` SubscriptionImpls
+  static interface Signal {};
+  enum Cancel implements Signal { Instance; };
+  enum Subscribe implements Signal { Instance; };
+  enum Send implements Signal { Instance; };
+  static final class Request implements Signal {
+    final long n;
+    Request(final long n) {
+      this.n = n;
+    }
+  };
+
+  // This is our implementation of the Reactive Streams `Subscription`,
+  // which represents the association between a `Publisher` and a `Subscriber`.
+  final class SubscriptionImpl implements Subscription, Runnable {
+    final Subscriber<? super T> subscriber; // We need a reference to the `Subscriber` so we can talk to it
+    private boolean cancelled = false; // This flag will track whether this `Subscription` is to be considered cancelled or not
+    private long demand = 0; // Here we track the current demand, i.e. what has been requested but not yet delivered
+    private Iterator<T> iterator; // This is our cursor into the data stream, which we will send to the `Subscriber`
+
+    SubscriptionImpl(final Subscriber<? super T> subscriber) {
+      // As per rule 1.09, we need to throw a `java.lang.NullPointerException` if the `Subscriber` is `null`
+      if (subscriber == null) throw null;
+      this.subscriber = subscriber;
+    }
+
+    // This `ConcurrentLinkedQueue` will track signals that are sent to this `Subscription`, like `request` and `cancel`
+    private final ConcurrentLinkedQueue<Signal> inboundSignals = new ConcurrentLinkedQueue<Signal>();
+
+    // We are using this `AtomicBoolean` to make sure that this `Subscription` doesn't run concurrently with itself,
+    // which would violate rule 1.3 among others (no concurrent notifications).
+    private final AtomicBoolean on = new AtomicBoolean(false);
+
+    // This method will register inbound demand from our `Subscriber` and validate it against rule 3.9 and rule 3.17
+    private void doRequest(final long n) {
+      if (n < 1)
+        terminateDueTo(new IllegalArgumentException(subscriber + " violated the Reactive Streams rule 3.9 by requesting a non-positive number of elements."));
+      else if (demand + n < 1) {
+        // As governed by rule 3.17, when demand overflows `Long.MAX_VALUE` we treat the signalled demand as "effectively unbounded"
+        demand = Long.MAX_VALUE;  // Here we protect from the overflow and treat it as "effectively unbounded"
+        doSend(); // Then we proceed with sending data downstream
+      } else {
+        demand += n; // Here we record the downstream demand
+        doSend(); // Then we can proceed with sending data downstream
+      }
+    }
+
+    // This handles cancellation requests, and is idempotent, thread-safe and not synchronously performing heavy computations as specified in rule 3.5
+    private void doCancel() {
+      cancelled = true;
+    }
+
+    // Instead of executing `subscriber.onSubscribe` synchronously from within `Publisher.subscribe`
+    // we execute it asynchronously, this is to avoid executing the user code (`Iterable.iterator`) on the calling thread.
+    // It also makes it easier to follow rule 1.9
+    private void doSubscribe() {
+      try {
+        iterator = elements.iterator();
+        if (iterator == null)
+          iterator = Collections.<T>emptyList().iterator(); // So we can assume that `iterator` is never null
+      } catch(final Throwable t) {
+        subscriber.onSubscribe(new Subscription() { // We need to make sure we signal onSubscribe before onError, obeying rule 1.9
+          @Override public void cancel() {}
+          @Override public void request(long n) {}
+        });
+        terminateDueTo(t); // Here we send onError, obeying rule 1.09
+      }
+
+      if (!cancelled) {
+        // Deal with setting up the subscription with the subscriber
+        try {
+          subscriber.onSubscribe(this);
+        } catch(final Throwable t) { // Due diligence to obey 2.13
+          terminateDueTo(new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onSubscribe.", t));
+        }
+
+        // Deal with already complete iterators promptly
+        boolean hasElements = false;
+        try {
+          hasElements = iterator.hasNext();
+        } catch(final Throwable t) {
+          terminateDueTo(t); // If hasNext throws, there's something wrong and we need to signal onError as per 1.2, 1.4,
+        }
+
+        // If we don't have anything to deliver, we're already done, so lets do the right thing and
+        // not wait for demand to deliver `onComplete` as per rule 1.2 and 1.3
+        if (!hasElements) {
+          try {
+            doCancel(); // Rule 1.6 says we need to consider the `Subscription` cancelled when `onComplete` is signalled
+            subscriber.onComplete();
+          } 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.
+            (new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onComplete.", t)).printStackTrace(System.err);
+          }
+        }
+      }
+    }
+
+    // This is our behavior for producing elements downstream
+    private void doSend() {
+      try {
+        // In order to play nice with the `Executor` we will only send at-most `batchSize` before
+        // rescheduing ourselves and relinquishing the current thread.
+        int leftInBatch = batchSize;
+        do {
+          T next;
+          boolean hasNext;
+          try {
+            next = iterator.next(); // We have already checked `hasNext` when subscribing, so we can fall back to testing -after- `next` is called.
+            hasNext = iterator.hasNext(); // Need to keep track of End-of-Stream
+          } catch (final Throwable t) {
+            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
+            return;
+          }
+          subscriber.onNext(next); // Then we signal the next element downstream to the `Subscriber`
+          if (!hasNext) { // If we are at End-of-Stream
+            doCancel(); // We need to consider this `Subscription` as cancelled as per rule 1.6
+            subscriber.onComplete(); // Then we signal `onComplete` as per rule 1.2 and 1.5
+          }
+        } while (!cancelled           // This makes sure that rule 1.8 is upheld, i.e. we need to stop signalling "eventually"
+                 && --leftInBatch > 0 // This makes sure that we only send `batchSize` number of elements in one go (so we can yield to other Runnables)
+                 && --demand > 0);    // This makes sure that rule 1.1 is upheld (sending more than was demanded)
+
+        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
+          signal(Send.Instance);
+      } catch(final Throwable t) {
+        // 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.
+        doCancel(); // Make sure that we are cancelled, since we cannot do anything else since the `Subscriber` is faulty.
+        (new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onNext or onComplete.", t)).printStackTrace(System.err);
+      }
+    }
+
+    // This is a helper method to ensure that we always `cancel` when we signal `onError` as per rule 1.6
+    private void terminateDueTo(final Throwable t) {
+      cancelled = true; // When we signal onError, the subscription must be considered as cancelled, as per rule 1.6
+      try {
+        subscriber.onError(t); // Then we signal the error downstream, to the `Subscriber`
+      } 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.
+        (new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 by throwing an exception from onError.", t2)).printStackTrace(System.err);
+      }
+    }
+
+    // What `signal` does is that it sends signals to the `Subscription` asynchronously
+    private void signal(final Signal signal) {
+      if (inboundSignals.offer(signal)) // No need to null-check here as ConcurrentLinkedQueue does this for us
+        tryScheduleToExecute(); // Then we try to schedule it for execution, if it isn't already
+    }
+
+    // This is the main "event loop" if you so will
+    @Override public final void run() {
+      if(on.get()) { // establishes a happens-before relationship with the end of the previous run
+        try {
+          final Signal s = inboundSignals.poll(); // We take a signal off the queue
+          if (!cancelled) { // to make sure that we follow rule 1.8, 3.6 and 3.7
+
+            // Below we simply unpack the `Signal`s and invoke the corresponding methods
+            if (s instanceof Request)
+              doRequest(((Request)s).n);
+            else if (s == Send.Instance)
+              doSend();
+            else if (s == Cancel.Instance)
+              doCancel();
+            else if (s == Subscribe.Instance)
+              doSubscribe();
+          }
+        } finally {
+          on.set(false); // establishes a happens-before relationship with the beginning of the next run
+          if(!inboundSignals.isEmpty()) // If we still have signals to process
+            tryScheduleToExecute(); // Then we try to schedule ourselves to execute again
+        }
+      }
+    }
+
+    // This method makes sure that this `Subscription` is only running on one Thread at a time,
+    // this is important to make sure that we follow rule 1.3
+    private final void tryScheduleToExecute() {
+      if(on.compareAndSet(false, true)) {
+        try {
+          executor.execute(this);
+        } catch(Throwable t) { // If we can't run on the `Executor`, we need to fail gracefully
+          if (!cancelled) {
+            doCancel(); // First of all, this failure is not recoverable, so we need to follow rule 1.4 and 1.6
+            try {
+              terminateDueTo(new IllegalStateException("Publisher terminated due to unavailable Executor.", t));
+            } finally {
+              inboundSignals.clear(); // We're not going to need these anymore
+              // This subscription is cancelled by now, but letting it become schedulable again means
+              // that we can drain the inboundSignals queue if anything arrives after clearing
+              on.set(false);
+            }
+          }
+        }
+      }
+    }
+
+    // Our implementation of `Subscription.request` sends a signal to the Subscription that more elements are in demand
+    @Override public void request(final long n) {
+      signal(new Request(n));
+    }
+    // Our implementation of `Subscription.cancel` sends a signal to the Subscription that the `Subscriber` is not interested in any more elements
+    @Override public void cancel() {
+      signal(Cancel.Instance);
+    }
+    // The reason for the `init` method is that we want to ensure the `SubscriptionImpl`
+    // is completely constructed before it is exposed to the thread pool, therefor this
+    // method is only intended to be invoked once, and immediately after the constructor has
+    // finished.
+    void init() {
+      signal(Subscribe.Instance);
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/example/unicast/AsyncSubscriber.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.example.unicast;
+
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * 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.
+ */
+public abstract class AsyncSubscriber<T> implements Subscriber<T>, Runnable {
+
+  // Signal represents the asynchronous protocol between the Publisher and Subscriber
+  private static interface Signal {}
+
+  private enum OnComplete implements Signal { Instance; }
+
+  private static class OnError implements Signal {
+    public final Throwable error;
+    public OnError(final Throwable error) { this.error = error; }
+  }
+
+  private static class OnNext<T> implements Signal {
+    public final T next;
+    public OnNext(final T next) { this.next = next; }
+  }
+
+  private static class OnSubscribe implements Signal {
+    public final Subscription subscription;
+    public OnSubscribe(final Subscription subscription) { this.subscription = subscription; }
+  }
+
+  private Subscription subscription; // Obeying rule 3.1, we make this private!
+  private boolean done; // It's useful to keep track of whether this Subscriber is done or not
+  private final Executor executor; // This is the Executor we'll use to be asynchronous, obeying rule 2.2
+
+  // Only one constructor, and it's only accessible for the subclasses
+  protected AsyncSubscriber(Executor executor) {
+    if (executor == null) throw null;
+    this.executor = executor;
+  }
+
+  // Showcases a convenience method to idempotently marking the Subscriber as "done", so we don't want to process more elements
+  // herefor we also need to cancel our `Subscription`.
+  private final void done() {
+    //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.
+    done = true; // If `whenNext` throws an exception, let's consider ourselves done (not accepting more elements)
+    if (subscription != null) { // If we are bailing out before we got a `Subscription` there's little need for cancelling it.
+      try {
+        subscription.cancel(); // Cancel the subscription
+      } catch(final Throwable t) {
+        //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+        (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+      }
+    }
+  }
+
+  // This method is invoked when the OnNext signals arrive
+  // Returns whether more elements are desired or not, and if no more elements are desired,
+  // for convenience.
+  protected abstract boolean whenNext(final T element);
+
+  // This method is invoked when the OnComplete signal arrives
+  // override this method to implement your own custom onComplete logic.
+  protected void whenComplete() { }
+
+  // This method is invoked if the OnError signal arrives
+  // override this method to implement your own custom onError logic.
+  protected void whenError(Throwable error) { }
+
+  private final void handleOnSubscribe(final Subscription s) {
+    if (s == null) {
+      // Getting a null `Subscription` here is not valid so lets just ignore it.
+    } else if (subscription != null) { // If someone has made a mistake and added this Subscriber multiple times, let's handle it gracefully
+      try {
+        s.cancel(); // Cancel the additional subscription to follow rule 2.5
+      } catch(final Throwable t) {
+        //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+        (new IllegalStateException(s + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+      }
+    } else {
+      // We have to assign it locally before we use it, if we want to be a synchronous `Subscriber`
+      // Because according to rule 3.10, the Subscription is allowed to call `onNext` synchronously from within `request`
+      subscription = s;
+      try {
+        // If we want elements, according to rule 2.1 we need to call `request`
+        // And, according to rule 3.2 we are allowed to call this synchronously from within the `onSubscribe` method
+        s.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+      } catch(final Throwable t) {
+        // Subscription.request is not allowed to throw according to rule 3.16
+        (new IllegalStateException(s + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+      }
+    }
+  }
+
+  private final void handleOnNext(final T element) {
+    if (!done) { // If we aren't already done
+      if(subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+        // Check for spec violation of 2.1 and 1.09
+        (new IllegalStateException("Someone violated the Reactive Streams rule 1.09 and 2.1 by signalling OnNext before `Subscription.request`. (no Subscription)")).printStackTrace(System.err);
+      } else {
+        try {
+          if (whenNext(element)) {
+            try {
+              subscription.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+            } catch(final Throwable t) {
+              // Subscription.request is not allowed to throw according to rule 3.16
+              (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+            }
+          } else {
+            done(); // This is legal according to rule 2.6
+          }
+        } catch(final Throwable t) {
+          done();
+          try {
+            onError(t);
+          } catch(final Throwable t2) {
+            //Subscriber.onError is not allowed to throw an exception, according to rule 2.13
+            (new IllegalStateException(this + " violated the Reactive Streams rule 2.13 by throwing an exception from onError.", t2)).printStackTrace(System.err);
+          }
+        }
+      }
+    }
+  }
+
+  // Here it is important that we do not violate 2.2 and 2.3 by calling methods on the `Subscription` or `Publisher`
+  private void handleOnComplete() {
+    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+      // Publisher is not allowed to signal onComplete before onSubscribe according to rule 1.09
+      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onComplete prior to onSubscribe.")).printStackTrace(System.err);
+    } else {
+      done = true; // Obey rule 2.4
+      whenComplete();
+    }
+  }
+
+  // Here it is important that we do not violate 2.2 and 2.3 by calling methods on the `Subscription` or `Publisher`
+  private void handleOnError(final Throwable error) {
+    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+      // Publisher is not allowed to signal onError before onSubscribe according to rule 1.09
+      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onError prior to onSubscribe.")).printStackTrace(System.err);
+    } else {
+      done = true; // Obey rule 2.4
+      whenError(error);
+    }
+  }
+
+  // We implement the OnX methods on `Subscriber` to send Signals that we will process asycnhronously, but only one at a time
+
+  @Override public final void onSubscribe(final Subscription s) {
+    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Subscription` is `null`
+    if (s == null) throw null;
+
+    signal(new OnSubscribe(s));
+  }
+
+  @Override public final void onNext(final T element) {
+    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `element` is `null`
+    if (element == null) throw null;
+
+    signal(new OnNext<T>(element));
+  }
+
+  @Override public final void onError(final Throwable t) {
+    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Throwable` is `null`
+    if (t == null) throw null;
+
+    signal(new OnError(t));
+  }
+
+  @Override public final void onComplete() {
+     signal(OnComplete.Instance);
+  }
+
+  // This `ConcurrentLinkedQueue` will track signals that are sent to this `Subscriber`, like `OnComplete` and `OnNext` ,
+  // and obeying rule 2.11
+  private final ConcurrentLinkedQueue<Signal> inboundSignals = new ConcurrentLinkedQueue<Signal>();
+
+  // We are using this `AtomicBoolean` to make sure that this `Subscriber` doesn't run concurrently with itself,
+  // obeying rule 2.7 and 2.11
+  private final AtomicBoolean on = new AtomicBoolean(false);
+
+   @SuppressWarnings("unchecked")
+   @Override public final void run() {
+    if(on.get()) { // establishes a happens-before relationship with the end of the previous run
+      try {
+        final Signal s = inboundSignals.poll(); // We take a signal off the queue
+        if (!done) { // If we're done, we shouldn't process any more signals, obeying rule 2.8
+          // Below we simply unpack the `Signal`s and invoke the corresponding methods
+          if (s instanceof OnNext<?>)
+            handleOnNext(((OnNext<T>)s).next);
+          else if (s instanceof OnSubscribe)
+            handleOnSubscribe(((OnSubscribe)s).subscription);
+          else if (s instanceof OnError) // We are always able to handle OnError, obeying rule 2.10
+            handleOnError(((OnError)s).error);
+          else if (s == OnComplete.Instance) // We are always able to handle OnComplete, obeying rule 2.9
+            handleOnComplete();
+        }
+      } finally {
+        on.set(false); // establishes a happens-before relationship with the beginning of the next run
+        if(!inboundSignals.isEmpty()) // If we still have signals to process
+          tryScheduleToExecute(); // Then we try to schedule ourselves to execute again
+      }
+    }
+  }
+
+  // What `signal` does is that it sends signals to the `Subscription` asynchronously
+  private void signal(final Signal signal) {
+    if (inboundSignals.offer(signal)) // No need to null-check here as ConcurrentLinkedQueue does this for us
+      tryScheduleToExecute(); // Then we try to schedule it for execution, if it isn't already
+  }
+
+  // This method makes sure that this `Subscriber` is only executing on one Thread at a time
+  private final void tryScheduleToExecute() {
+    if(on.compareAndSet(false, true)) {
+      try {
+        executor.execute(this);
+      } catch(Throwable t) { // If we can't run on the `Executor`, we need to fail gracefully and not violate rule 2.13
+        if (!done) {
+          try {
+            done(); // First of all, this failure is not recoverable, so we need to cancel our subscription
+          } finally {
+            inboundSignals.clear(); // We're not going to need these anymore
+            // This subscription is cancelled by now, but letting the Subscriber become schedulable again means
+            // that we can drain the inboundSignals queue if anything arrives after clearing
+            on.set(false);
+          }
+        }
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/example/unicast/InfiniteIncrementNumberPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.example.unicast;
+
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+
+import org.reactivestreams.Subscription;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Publisher;
+
+public class InfiniteIncrementNumberPublisher extends AsyncIterablePublisher<Integer> {
+    public InfiniteIncrementNumberPublisher(final Executor executor) {
+        super(new Iterable<Integer>() {
+          @Override public Iterator<Integer> iterator() {
+            return new Iterator<Integer>() {
+              private int at = 0;
+              @Override public boolean hasNext() { return true; }
+              @Override public Integer next() { return at++; } // Wraps around on overflow
+              @Override public void remove() { throw new UnsupportedOperationException(); }
+            };
+          }
+        }, executor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/example/unicast/NumberIterablePublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.example.unicast;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Publisher;
+
+public class NumberIterablePublisher extends AsyncIterablePublisher<Integer> {
+    public NumberIterablePublisher(final int from, final int to, final Executor executor) {
+        super(new Iterable<Integer>() {
+          { if(from > to) throw new IllegalArgumentException("from must be equal or greater than to!"); }
+          @Override public Iterator<Integer> iterator() {
+            return new Iterator<Integer>() {
+              private int at = from;
+              @Override public boolean hasNext() { return at < to; }
+              @Override public Integer next() {
+                if (!hasNext()) return Collections.<Integer>emptyList().iterator().next();
+                else return at++;
+              }
+              @Override public void remove() { throw new UnsupportedOperationException(); }
+            };
+          }
+        }, executor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/example/unicast/RangePublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.example.unicast;
+
+import org.reactivestreams.*;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A synchronous implementation of the {@link Publisher} that can
+ * be subscribed to multiple times and each individual subscription
+ * will receive range of monotonically increasing integer values on demand.
+ */
+public final class RangePublisher implements Publisher<Integer> {
+
+    /** The starting value of the range. */
+    final int start;
+
+    /** The number of items to emit. */
+    final int count;
+
+    /**
+     * Constructs a RangePublisher instance with the given start and count values
+     * that yields a sequence of [start, start + count).
+     * @param start the starting value of the range
+     * @param count the number of items to emit
+     */
+    public RangePublisher(int start, int count) {
+        this.start = start;
+        this.count = count;
+    }
+
+    @Override
+    public void subscribe(Subscriber<? super Integer> subscriber) {
+        // As per rule 1.11, we have decided to support multiple subscribers
+        // in a unicast configuration for this `Publisher` implementation.
+
+        // As per rule 1.09, we need to throw a `java.lang.NullPointerException`
+        // if the `Subscriber` is `null`
+        if (subscriber == null) throw null;
+
+        // As per 2.13, this method must return normally (i.e. not throw).
+        try {
+            subscriber.onSubscribe(new RangeSubscription(subscriber, start, start + count));
+        } catch (Throwable ex) {
+            new IllegalStateException(subscriber + " violated the Reactive Streams rule 2.13 " +
+                    "by throwing an exception from onSubscribe.", ex)
+                    // When onSubscribe fails this way, we don't know what state the
+                    // subscriber is thus calling onError may cause more crashes.
+                    .printStackTrace();
+        }
+    }
+
+    /**
+     * A Subscription implementation that holds the current downstream
+     * requested amount and responds to the downstream's request() and
+     * cancel() calls.
+     */
+    static final class RangeSubscription
+            // We are using this `AtomicLong` to make sure that this `Subscription`
+            // doesn't run concurrently with itself, which would violate rule 1.3
+            // among others (no concurrent notifications).
+            // The atomic transition from 0L to N > 0L will ensure this.
+            extends AtomicLong implements Subscription {
+
+        private static final long serialVersionUID = -9000845542177067735L;
+
+        /** The Subscriber we are emitting integer values to. */
+        final Subscriber<? super Integer> downstream;
+
+        /** The end index (exclusive). */
+        final int end;
+
+        /**
+         * The current index and within the [start, start + count) range that
+         * will be emitted as downstream.onNext().
+         */
+        int index;
+
+        /**
+         * Indicates the emission should stop.
+         */
+        volatile boolean cancelled;
+
+        /**
+         * Holds onto the IllegalArgumentException (containing the offending stacktrace)
+         * indicating there was a non-positive request() call from the downstream.
+         */
+        volatile Throwable invalidRequest;
+
+        /**
+         * Constructs a stateful RangeSubscription that emits signals to the given
+         * downstream from an integer range of [start, end).
+         * @param downstream the Subscriber receiving the integer values and the completion signal.
+         * @param start the first integer value emitted, start of the range
+         * @param end the end of the range, exclusive
+         */
+        RangeSubscription(Subscriber<? super Integer> downstream, int start, int end) {
+            this.downstream = downstream;
+            this.index = start;
+            this.end = end;
+        }
+
+        // This method will register inbound demand from our `Subscriber` and
+        // validate it against rule 3.9 and rule 3.17
+        @Override
+        public void request(long n) {
+            // Non-positive requests should be honored with IllegalArgumentException
+            if (n <= 0L) {
+                invalidRequest = new IllegalArgumentException("§3.9: non-positive requests are not allowed!");
+                n = 1;
+            }
+            // Downstream requests are cumulative and may come from any thread
+            for (;;) {
+                long requested = get();
+                long update = requested + n;
+                // As governed by rule 3.17, when demand overflows `Long.MAX_VALUE`
+                // we treat the signalled demand as "effectively unbounded"
+                if (update < 0L) {
+                    update = Long.MAX_VALUE;
+                }
+                // atomically update the current requested amount
+                if (compareAndSet(requested, update)) {
+                    // if there was no prior request amount, we start the emission loop
+                    if (requested == 0L) {
+                        emit(update);
+                    }
+                    break;
+                }
+            }
+        }
+
+        // This handles cancellation requests, and is idempotent, thread-safe and not
+        // synchronously performing heavy computations as specified in rule 3.5
+        @Override
+        public void cancel() {
+            // Indicate to the emission loop it should stop.
+            cancelled = true;
+        }
+
+        void emit(long currentRequested) {
+            // Load fields to avoid re-reading them from memory due to volatile accesses in the loop.
+            Subscriber<? super Integer> downstream = this.downstream;
+            int index = this.index;
+            int end = this.end;
+            int emitted = 0;
+
+            try {
+                for (; ; ) {
+                    // Check if there was an invalid request and then report its exception
+                    // as mandated by rule 3.9. The stacktrace in it should
+                    // help locate the faulty logic in the Subscriber.
+                    Throwable invalidRequest = this.invalidRequest;
+                    if (invalidRequest != null) {
+                        // When we signal onError, the subscription must be considered as cancelled, as per rule 1.6
+                        cancelled = true;
+
+                        downstream.onError(invalidRequest);
+                        return;
+                    }
+
+                    // Loop while the index hasn't reached the end and we haven't
+                    // emitted all that's been requested
+                    while (index != end && emitted != currentRequested) {
+                        // to make sure that we follow rule 1.8, 3.6 and 3.7
+                        // We stop if cancellation was requested.
+                        if (cancelled) {
+                            return;
+                        }
+
+                        downstream.onNext(index);
+
+                        // Increment the index for the next possible emission.
+                        index++;
+                        // Increment the emitted count to prevent overflowing the downstream.
+                        emitted++;
+                    }
+
+                    // If the index reached the end, we complete the downstream.
+                    if (index == end) {
+                        // to make sure that we follow rule 1.8, 3.6 and 3.7
+                        // Unless cancellation was requested by the last onNext.
+                        if (!cancelled) {
+                            // We need to consider this `Subscription` as cancelled as per rule 1.6
+                            // Note, however, that this state is not observable from the outside
+                            // world and since we leave the loop with requested > 0L, any
+                            // further request() will never trigger the loop.
+                            cancelled = true;
+
+                            downstream.onComplete();
+                        }
+                        return;
+                    }
+
+                    // Did the requested amount change while we were looping?
+                    long freshRequested = get();
+                    if (freshRequested == currentRequested) {
+                        // Save where the loop has left off: the next value to be emitted
+                        this.index = index;
+                        // Atomically subtract the previously requested (also emitted) amount
+                        currentRequested = addAndGet(-currentRequested);
+                        // If there was no new request in between get() and addAndGet(), we simply quit
+                        // The next 0 to N transition in request() will trigger the next emission loop.
+                        if (currentRequested == 0L) {
+                            break;
+                        }
+                        // Looks like there were more async requests, reset the emitted count and continue.
+                        emitted = 0;
+                    } else {
+                        // Yes, avoid the atomic subtraction and resume.
+                        // emitted != currentRequest in this case and index
+                        // still points to the next value to be emitted
+                        currentRequested = freshRequested;
+                    }
+                }
+            } catch (Throwable ex) {
+                // We can only get here if `onNext`, `onError` or `onComplete` threw, and they
+                // are not allowed to according to 2.13, so we can only cancel and log here.
+                // If `onError` throws an exception, this is a spec violation according to rule 1.9,
+                // and all we can do is to log it.
+
+                // Make sure that we are cancelled, since we cannot do anything else
+                // since the `Subscriber` is faulty.
+                cancelled = true;
+
+                // We can't report the failure to onError as the Subscriber is unreliable.
+                (new IllegalStateException(downstream + " violated the Reactive Streams rule 2.13 by " +
+                        "throwing an exception from onNext, onError or onComplete.", ex))
+                        .printStackTrace();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/example/unicast/SyncSubscriber.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.example.unicast;
+
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+
+/**
+ * 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.
+ */
+public abstract class SyncSubscriber<T> implements Subscriber<T> {
+  private Subscription subscription; // Obeying rule 3.1, we make this private!
+  private boolean done = false;
+
+  @Override public void onSubscribe(final Subscription s) {
+    // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Subscription` is `null`
+    if (s == null) throw null;
+
+    if (subscription != null) { // If someone has made a mistake and added this Subscriber multiple times, let's handle it gracefully
+      try {
+        s.cancel(); // Cancel the additional subscription
+      } catch(final Throwable t) {
+        //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+        (new IllegalStateException(s + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+      }
+    } else {
+      // We have to assign it locally before we use it, if we want to be a synchronous `Subscriber`
+      // Because according to rule 3.10, the Subscription is allowed to call `onNext` synchronously from within `request`
+      subscription = s;
+      try {
+        // If we want elements, according to rule 2.1 we need to call `request`
+        // And, according to rule 3.2 we are allowed to call this synchronously from within the `onSubscribe` method
+        s.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+      } catch(final Throwable t) {
+        // Subscription.request is not allowed to throw according to rule 3.16
+        (new IllegalStateException(s + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+      }
+    }
+  }
+
+  @Override public void onNext(final T element) {
+    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onNext prior to onSubscribe.")).printStackTrace(System.err);
+    } else {
+      // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `element` is `null`
+      if (element == null) throw null;
+
+      if (!done) { // If we aren't already done
+        try {
+          if (whenNext(element)) {
+            try {
+              subscription.request(1); // Our Subscriber is unbuffered and modest, it requests one element at a time
+            } catch (final Throwable t) {
+              // Subscription.request is not allowed to throw according to rule 3.16
+              (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.16 by throwing an exception from request.", t)).printStackTrace(System.err);
+            }
+          } else {
+            done();
+          }
+        } catch (final Throwable t) {
+          done();
+          try {
+            onError(t);
+          } catch (final Throwable t2) {
+            //Subscriber.onError is not allowed to throw an exception, according to rule 2.13
+            (new IllegalStateException(this + " violated the Reactive Streams rule 2.13 by throwing an exception from onError.", t2)).printStackTrace(System.err);
+          }
+        }
+      }
+    }
+  }
+
+  // Showcases a convenience method to idempotently marking the Subscriber as "done", so we don't want to process more elements
+  // herefor we also need to cancel our `Subscription`.
+  private void done() {
+    //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.
+    done = true; // If we `whenNext` throws an exception, let's consider ourselves done (not accepting more elements)
+    try {
+      subscription.cancel(); // Cancel the subscription
+    } catch(final Throwable t) {
+      //Subscription.cancel is not allowed to throw an exception, according to rule 3.15
+      (new IllegalStateException(subscription + " violated the Reactive Streams rule 3.15 by throwing an exception from cancel.", t)).printStackTrace(System.err);
+    }
+  }
+
+  // This method is left as an exercise to the reader/extension point
+  // Returns whether more elements are desired or not, and if no more elements are desired
+  protected abstract boolean whenNext(final T element);
+
+  @Override public void onError(final Throwable t) {
+    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onError prior to onSubscribe.")).printStackTrace(System.err);
+    } else {
+      // As per rule 2.13, we need to throw a `java.lang.NullPointerException` if the `Throwable` is `null`
+      if (t == null) throw null;
+      // Here we are not allowed to call any methods on the `Subscription` or the `Publisher`, as per rule 2.3
+      // And anyway, the `Subscription` is considered to be cancelled if this method gets called, as per rule 2.4
+    }
+  }
+
+  @Override public void onComplete() {
+    if (subscription == null) { // Technically this check is not needed, since we are expecting Publishers to conform to the spec
+      (new IllegalStateException("Publisher violated the Reactive Streams rule 1.09 signalling onComplete prior to onSubscribe.")).printStackTrace(System.err);
+    } else {
+      // Here we are not allowed to call any methods on the `Subscription` or the `Publisher`, as per rule 2.3
+      // And anyway, the `Subscription` is considered to be cancelled if this method gets called, as per rule 2.4
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/IdentityProcessorVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck;
+
+import org.reactivestreams.Processor;
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+import org.reactivestreams.tck.TestEnvironment.Promise;
+import org.reactivestreams.tck.flow.support.Function;
+import org.reactivestreams.tck.flow.support.SubscriberWhiteboxVerificationRules;
+import org.reactivestreams.tck.flow.support.PublisherVerificationRules;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class IdentityProcessorVerification<T> extends WithHelperPublisher<T>
+  implements SubscriberWhiteboxVerificationRules, PublisherVerificationRules {
+
+  private final TestEnvironment env;
+
+  ////////////////////// DELEGATED TO SPECS //////////////////////
+
+  // for delegating tests
+  private final SubscriberWhiteboxVerification<T> subscriberVerification;
+
+  // for delegating tests
+  private final PublisherVerification<T> publisherVerification;
+
+  ////////////////// END OF DELEGATED TO SPECS //////////////////
+
+  // number of elements the processor under test must be able ot buffer,
+  // without dropping elements. Defaults to `TestEnvironment.TEST_BUFFER_SIZE`.
+  private final int processorBufferSize;
+
+  /**
+   * Test class must specify the expected time it takes for the publisher to
+   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+   *
+   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+   */
+  @SuppressWarnings("unused")
+  public IdentityProcessorVerification(final TestEnvironment env) {
+    this(env, PublisherVerification.envPublisherReferenceGCTimeoutMillis(), TestEnvironment.TEST_BUFFER_SIZE);
+  }
+
+  /**
+   * Test class must specify the expected time it takes for the publisher to
+   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+   *
+   * The processor will be required to be able to buffer {@code TestEnvironment.TEST_BUFFER_SIZE} elements.
+   *
+   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+   */
+  @SuppressWarnings("unused")
+  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+    this(env, publisherReferenceGCTimeoutMillis, TestEnvironment.TEST_BUFFER_SIZE);
+  }
+
+  /**
+   * Test class must specify the expected time it takes for the publisher to
+   * shut itself down when the the last downstream {@code Subscription} is cancelled.
+   *
+   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+   * @param processorBufferSize            number of elements the processor is required to be able to buffer.
+   */
+  public IdentityProcessorVerification(final TestEnvironment env, long publisherReferenceGCTimeoutMillis, int processorBufferSize) {
+    this.env = env;
+    this.processorBufferSize = processorBufferSize;
+
+    this.subscriberVerification = new SubscriberWhiteboxVerification<T>(env) {
+      @Override
+      public Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe) {
+        return IdentityProcessorVerification.this.createSubscriber(probe);
+      }
+
+      @Override public T createElement(int element) {
+        return IdentityProcessorVerification.this.createElement(element);
+      }
+
+      @Override
+      public Publisher<T> createHelperPublisher(long elements) {
+        return IdentityProcessorVerification.this.createHelperPublisher(elements);
+      }
+    };
+
+    publisherVerification = new PublisherVerification<T>(env, publisherReferenceGCTimeoutMillis) {
+      @Override
+      public Publisher<T> createPublisher(long elements) {
+        return IdentityProcessorVerification.this.createPublisher(elements);
+      }
+
+      @Override
+      public Publisher<T> createFailedPublisher() {
+        return IdentityProcessorVerification.this.createFailedPublisher();
+      }
+
+      @Override
+      public long maxElementsFromPublisher() {
+        return IdentityProcessorVerification.this.maxElementsFromPublisher();
+      }
+
+      @Override
+      public long boundedDepthOfOnNextAndRequestRecursion() {
+        return IdentityProcessorVerification.this.boundedDepthOfOnNextAndRequestRecursion();
+      }
+
+      @Override
+      public boolean skipStochasticTests() {
+        return IdentityProcessorVerification.this.skipStochasticTests();
+      }
+    };
+  }
+
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a {@link Processor}, which simply forwards all stream elements from its upstream
+   * to its downstream. It must be able to internally buffer the given number of elements.
+   *
+   * @param bufferSize number of elements the processor is required to be able to buffer.
+   */
+  public abstract Processor<T, T> createIdentityProcessor(int bufferSize);
+
+  /**
+   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+   *
+   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+   *
+   * If you want to ignore these additional tests, return {@code null} from this method.
+   */
+  public abstract Publisher<T> createFailedPublisher();
+
+  /**
+   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+   *
+   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+   *
+   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+   */
+  public long maxElementsFromPublisher() {
+    return Long.MAX_VALUE - 1;
+  }
+
+  /**
+   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+   * recursive calls to exceed the number returned by this method.
+   *
+   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+   */
+  public long boundedDepthOfOnNextAndRequestRecursion() {
+    return 1;
+  }
+
+  /**
+   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+   * Stochastic in this case means that the Rule is impossible or infeasible to deterministically verify—
+   * usually this means that this test case can yield false positives ("be green") even if for some case,
+   * the given implementation may violate the tested behaviour.
+   */
+  public boolean skipStochasticTests() {
+    return false;
+  }
+
+  /**
+   * Describes the tested implementation in terms of how many subscribers they can support.
+   * Some tests require the {@code Publisher} under test to support multiple Subscribers,
+   * yet the spec does not require all publishers to be able to do so, thus – if an implementation
+   * supports only a limited number of subscribers (e.g. only 1 subscriber, also known as "no fanout")
+   * you MUST return that number from this method by overriding it.
+   */
+  public long maxSupportedSubscribers() {
+      return Long.MAX_VALUE;
+  }
+
+  /**
+   * Override this method and return {@code true} if the {@link Processor} returned by the
+   * {@link #createIdentityProcessor(int)} coordinates its {@link Subscriber}s
+   * request amounts and only delivers onNext signals if all Subscribers have
+   * indicated (via their Subscription#request(long)) they are ready to receive elements.
+   */
+  public boolean doesCoordinatedEmission() {
+    return false;
+  }
+
+  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+
+  @BeforeMethod
+  public void setUp() throws Exception {
+    publisherVerification.setUp();
+    subscriberVerification.setUp();
+  }
+
+  ////////////////////// PUBLISHER RULES VERIFICATION ///////////////////////////
+
+  // A Processor
+  //   must obey all Publisher rules on its publishing side
+  public Publisher<T> createPublisher(long elements) {
+    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+    final Publisher<T> pub = createHelperPublisher(elements);
+    pub.subscribe(processor);
+    return processor; // we run the PublisherVerification against this
+  }
+
+  @Override @Test
+  public void required_validate_maxElementsFromPublisher() throws Exception {
+    publisherVerification.required_validate_maxElementsFromPublisher();
+  }
+
+  @Override @Test
+  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+    publisherVerification.required_validate_boundedDepthOfOnNextAndRequestRecursion();
+  }
+
+  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" PUBLISHER //////////////////////
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+
+  @Test
+  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+    publisherVerification.required_createPublisher1MustProduceAStreamOfExactly1Element();
+  }
+
+  @Test
+  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+    publisherVerification.required_createPublisher3MustProduceAStreamOfExactly3Elements();
+  }
+
+  @Override @Test
+  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+    publisherVerification.required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements();
+  }
+
+  @Override @Test
+  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+    publisherVerification.required_spec102_maySignalLessThanRequestedAndTerminateSubscription();
+  }
+
+  @Override @Test
+  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+    publisherVerification.stochastic_spec103_mustSignalOnMethodsSequentially();
+  }
+
+  @Override @Test
+  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+    publisherVerification.optional_spec104_mustSignalOnErrorWhenFails();
+  }
+
+  @Override @Test
+  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+    publisherVerification.required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates();
+  }
+
+  @Override @Test
+  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+    publisherVerification.optional_spec105_emptyStreamMustTerminateBySignallingOnComplete();
+  }
+
+  @Override @Test
+  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+    publisherVerification.untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled();
+  }
+
+  @Override @Test
+  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+    publisherVerification.required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled();
+  }
+
+  @Override @Test
+  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+    publisherVerification.untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled();
+  }
+
+  @Override @Test
+  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+    publisherVerification.untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals();
+  }
+
+  @Override @Test
+  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+    publisherVerification.untested_spec109_subscribeShouldNotThrowNonFatalThrowable();
+  }
+
+  @Override @Test
+  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+    publisherVerification.required_spec109_subscribeThrowNPEOnNullSubscriber();
+  }
+
+  @Override @Test
+  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+    publisherVerification.required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe();
+  }
+
+  @Override @Test
+  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+    publisherVerification.required_spec109_mustIssueOnSubscribeForNonNullSubscriber();
+  }
+
+  @Override @Test
+  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+    publisherVerification.untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice();
+  }
+
+  @Override @Test
+  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+    publisherVerification.optional_spec111_maySupportMultiSubscribe();
+  }
+
+  @Override @Test
+  public void optional_spec111_registeredSubscribersMustReceiveOnNextOrOnCompleteSignals() throws Throwable {
+    publisherVerification.optional_spec111_registeredSubscribersMustReceiveOnNextOrOnCompleteSignals();
+  }
+
+  @Override @Test
+  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne();
+  }
+
+  @Override @Test
+  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront();
+  }
+
+  @Override @Test
+  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+    publisherVerification.optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected();
+  }
+
+  @Override @Test
+  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+    publisherVerification.required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe();
+  }
+
+  @Override @Test
+  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+    publisherVerification.required_spec303_mustNotAllowUnboundedRecursion();
+  }
+
+  @Override @Test
+  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+    publisherVerification.untested_spec304_requestShouldNotPerformHeavyComputations();
+  }
+
+  @Override @Test
+  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyComputation() throws Exception {
+    publisherVerification.untested_spec305_cancelMustNotSynchronouslyPerformHeavyComputation();
+  }
+
+  @Override @Test
+  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+    publisherVerification.required_spec306_afterSubscriptionIsCancelledRequestMustBeNops();
+  }
+
+  @Override @Test
+  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+    publisherVerification.required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops();
+  }
+
+  @Override @Test
+  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+    publisherVerification.required_spec309_requestZeroMustSignalIllegalArgumentException();
+  }
+
+  @Override @Test
+  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+    publisherVerification.required_spec309_requestNegativeNumberMustSignalIllegalArgumentException();
+  }
+
+  @Override @Test
+  public void optional_spec309_requestNegativeNumberMaySignalIllegalArgumentExceptionWithSpecificMessage() throws Throwable {
+    publisherVerification.optional_spec309_requestNegativeNumberMaySignalIllegalArgumentExceptionWithSpecificMessage();
+  }
+
+  @Override @Test
+  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+    publisherVerification.required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling();
+  }
+
+  @Override @Test
+  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+    publisherVerification.required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber();
+  }
+
+  @Override @Test
+  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+    publisherVerification.required_spec317_mustSupportAPendingElementCountUpToLongMaxValue();
+  }
+
+  @Override @Test
+  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+    publisherVerification.required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue();
+  }
+
+  @Override @Test
+  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+    publisherVerification.required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue();
+  }
+
+
+  /**
+   * Asks for a {@code Processor} that supports at least 2 {@code Subscriber}s at once and checks if two {@code Subscriber}s
+   * receive the same items and a terminal {@code Exception}.
+   * <p>
+   * If the {@code Processor} requests and/or emits items only when all of its {@code Subscriber}s have requested,
+   * override {@link #doesCoordinatedEmission()} and return {@code true} to indicate this property.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.4'>1.4</a> with multiple
+   * {@code Subscriber}s.
+   * <p>
+   * The test is not executed if {@link IdentityProcessorVerification#maxSupportedSubscribers()} is less than 2.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Processor} implementation:
+   * <ul>
+   * <li>The {@code TestEnvironment} has large enough timeout specified in case the {@code Processor} has some time-delay behavior.</li>
+   * <li>The {@code Processor} is able to fulfill requests of its {@code Subscriber}s independently of each other's requests or
+   * else override {@link #doesCoordinatedEmission()} and return {@code true} to indicate the test {@code Subscriber}s
+   * both have to request first.</li>
+   * </ul>
+   */
+  @Test
+  public void required_spec104_mustCallOnErrorOnAllItsSubscribersIfItEncountersANonRecoverableError() throws Throwable {
+    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+      @Override
+      public TestSetup apply(Long aLong) throws Throwable {
+        return new TestSetup(env, processorBufferSize) {{
+          final ManualSubscriberWithErrorCollection<T> sub1 = new ManualSubscriberWithErrorCollection<T>(env);
+          env.subscribe(processor, sub1);
+
+          final ManualSubscriberWithErrorCollection<T> sub2 = new ManualSubscriberWithErrorCollection<T>(env);
+          env.subscribe(processor, sub2);
+
+          final Exception ex = new RuntimeException("Test exception");
+
+          if (doesCoordinatedEmission()) {
+            sub1.request(1);
+            sub2.request(1);
+
+            expectRequest();
+
+            final T x = sendNextTFromUpstream();
+
+            expectNextElement(sub1, x);
+            expectNextElement(sub2, x);
+
+            sub1.request(1);
+            sub2.request(1);
+          } else {
+            sub1.request(1);
+
+            expectRequest(env.defaultTimeoutMillis(),
+                    "If the Processor coordinates requests/emissions when having multiple Subscribers"
+                    + " at once, please override doesCoordinatedEmission() to return true in this "
+                    + "IdentityProcessorVerification to allow this test to pass.");
+
+            final T x = sendNextTFromUpstream();
+            expectNextElement(sub1, x,
+                    "If the Processor coordinates requests/emissions when having multiple Subscribers"
+                            + " at once, please override doesCoordinatedEmission() to return true in this "
+                            + "IdentityProcessorVerification to allow this test to pass.");
+
+            sub1.request(1);
+
+            // sub1 has received one element, and has one demand pending
+            // sub2 has not yet requested anything
+          }
+          sendError(ex);
+
+          sub1.expectError(ex);
+          sub2.expectError(ex);
+
+          env.verifyNoAsyncErrorsNoDelay();
+        }};
+      }
+    });
+  }
+
+  ////////////////////// SUBSCRIBER RULES VERIFICATION ///////////////////////////
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+
+  // A Processor
+  //   must obey all Subscriber rules on its consuming side
+  public Subscriber<T> createSubscriber(final SubscriberWhiteboxVerification.WhiteboxSubscriberProbe<T> probe) {
+    final Processor<T, T> processor = createIdentityProcessor(processorBufferSize);
+    processor.subscribe(
+        new Subscriber<T>() {
+          private final Promise<Subscription> subs = new Promise<Subscription>(env);
+
+          @Override
+          public void onSubscribe(final Subscription subscription) {
+            if (env.debugEnabled()) {
+              env.debug(String.format("whiteboxSubscriber::onSubscribe(%s)", subscription));
+            }
+            if (subs.isCompleted()) subscription.cancel(); // the Probe must also pass subscriber verification
+
+            probe.registerOnSubscribe(new SubscriberWhiteboxVerification.SubscriberPuppet() {
+
+              @Override
+              public void triggerRequest(long elements) {
+                subscription.request(elements);
+              }
+
+              @Override
+              public void signalCancel() {
+                subscription.cancel();
+              }
+            });
+          }
+
+          @Override
+          public void onNext(T element) {
+            if (env.debugEnabled()) {
+              env.debug(String.format("whiteboxSubscriber::onNext(%s)", element));
+            }
+            probe.registerOnNext(element);
+          }
+
+          @Override
+          public void onComplete() {
+            if (env.debugEnabled()) {
+              env.debug("whiteboxSubscriber::onComplete()");
+            }
+            probe.registerOnComplete();
+          }
+
+          @Override
+          public void onError(Throwable cause) {
+            if (env.debugEnabled()) {
+              env.debug(String.format("whiteboxSubscriber::onError(%s)", cause));
+            }
+            probe.registerOnError(cause);
+          }
+        });
+
+    return processor; // we run the SubscriberVerification against this
+  }
+
+  ////////////////////// OTHER RULE VERIFICATION ///////////////////////////
+
+  // A Processor
+  //   must immediately pass on `onError` events received from its upstream to its downstream
+  @Test
+  public void mustImmediatelyPassOnOnErrorEventsReceivedFromItsUpstreamToItsDownstream() throws Exception {
+    new TestSetup(env, processorBufferSize) {{
+      final ManualSubscriberWithErrorCollection<T> sub = new ManualSubscriberWithErrorCollection<T>(env);
+      env.subscribe(processor, sub);
+
+      final Exception ex = new RuntimeException("Test exception");
+      sendError(ex);
+      sub.expectError(ex); // "immediately", i.e. without a preceding request
+
+      env.verifyNoAsyncErrorsNoDelay();
+    }};
+  }
+
+  /////////////////////// DELEGATED TESTS, A PROCESSOR "IS A" SUBSCRIBER //////////////////////
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#4.1
+
+  @Test
+  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+    subscriberVerification.required_exerciseWhiteboxHappyPath();
+  }
+
+  @Override @Test
+  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+    subscriberVerification.required_spec201_mustSignalDemandViaSubscriptionRequest();
+  }
+
+  @Override @Test
+  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+    subscriberVerification.untested_spec202_shouldAsynchronouslyDispatch();
+  }
+
+  @Override @Test
+  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete();
+  }
+
+  @Override @Test
+  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+    subscriberVerification.required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError();
+  }
+
+  @Override @Test
+  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+    subscriberVerification.untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError();
+  }
+
+  @Override @Test
+  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+    subscriberVerification.required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal();
+  }
+
+  @Override @Test
+  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+    subscriberVerification.untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid();
+  }
+
+  @Override @Test
+  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+    subscriberVerification.untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization();
+  }
+
+  @Override @Test
+  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+    subscriberVerification.required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel();
+  }
+
+  @Override @Test
+  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall();
+  }
+
+  @Override @Test
+  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+    subscriberVerification.required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall();
+  }
+
+  @Override @Test
+  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall();
+  }
+
+  @Override @Test
+  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+    subscriberVerification.required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall();
+  }
+
+  @Override @Test
+  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+    subscriberVerification.untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents();
+  }
+
+  @Override @Test
+  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+    subscriberVerification.untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation();
+  }
+
+  @Override @Test
+  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+    subscriberVerification.untested_spec213_failingOnSignalInvocation();
+  }
+
+  @Override @Test
+  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    subscriberVerification.required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull();
+  }
+  @Override @Test
+  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    subscriberVerification.required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull();
+  }
+  @Override @Test
+  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    subscriberVerification.required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull();
+  }
+
+  @Override @Test
+  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+    subscriberVerification.untested_spec301_mustNotBeCalledOutsideSubscriberContext();
+  }
+
+  @Override @Test
+  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+    subscriberVerification.required_spec308_requestMustRegisterGivenNumberElementsToBeProduced();
+  }
+
+  @Override @Test
+  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+    subscriberVerification.untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber();
+  }
+
+  @Override @Test
+  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+    subscriberVerification.untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError();
+  }
+
+  @Override @Test
+  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+    subscriberVerification.untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists();
+  }
+
+  @Override @Test
+  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+    subscriberVerification.untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError();
+  }
+
+  @Override @Test
+  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+    subscriberVerification.untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber();
+  }
+
+  /////////////////////// ADDITIONAL "COROLLARY" TESTS //////////////////////
+
+  /**
+   * Asks for a {@code Processor} that supports at least 2 {@code Subscriber}s at once and checks requests
+   * from {@code Subscriber}s will eventually lead to requests towards the upstream of the {@code Processor}.
+   * <p>
+   * If the {@code Processor} requests and/or emits items only when all of its {@code Subscriber}s have requested,
+   * override {@link #doesCoordinatedEmission()} and return {@code true} to indicate this property.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.4'>2.1</a> with multiple
+   * {@code Subscriber}s.
+   * <p>
+   * The test is not executed if {@link IdentityProcessorVerification#maxSupportedSubscribers()} is less than 2.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Processor} implementation:
+   * <ul>
+   * <li>The {@code TestEnvironment} has large enough timeout specified in case the {@code Processor} has some time-delay behavior.</li>
+   * <li>The {@code Processor} is able to fulfill requests of its {@code Subscriber}s independently of each other's requests or
+   * else override {@link #doesCoordinatedEmission()} and return {@code true} to indicate the test {@code Subscriber}s
+   * both have to request first.</li>
+   * </ul>
+   */
+  @Test
+  public void required_mustRequestFromUpstreamForElementsThatHaveBeenRequestedLongAgo() throws Throwable {
+    optionalMultipleSubscribersTest(2, new Function<Long,TestSetup>() {
+      @Override
+      public TestSetup apply(Long subscribers) throws Throwable {
+        return new TestSetup(env, processorBufferSize) {{
+          ManualSubscriber<T> sub1 = newSubscriber();
+          sub1.request(20);
+
+          long totalRequests = expectRequest();
+          final T x = sendNextTFromUpstream();
+          expectNextElement(sub1, x);
+
+          if (totalRequests == 1) {
+            totalRequests += expectRequest();
+          }
+          final T y = sendNextTFromUpstream();
+          expectNextElement(sub1, y);
+
+          if (totalRequests == 2) {
+            totalRequests += expectRequest();
+          }
+
+          final ManualSubscriber<T> sub2 = newSubscriber();
+
+          // sub1 now has 18 pending
+          // sub2 has 0 pending
+
+          if (doesCoordinatedEmission()) {
+            sub2.expectNone(); // since sub2 hasn't requested anything yet
+
+            sub2.request(1);
+
+            final T z = sendNextTFromUpstream();
+            expectNextElement(sub1, z);
+            expectNextElement(sub2, z);
+          } else {
+            final T z = sendNextTFromUpstream();
+            expectNextElement(sub1, z,
+                    "If the Processor coordinates requests/emissions when having multiple Subscribers"
+                            + " at once, please override doesCoordinatedEmission() to return true in this "
+                            + "IdentityProcessorVerification to allow this test to pass.");
+            sub2.expectNone(); // since sub2 hasn't requested anything yet
+
+            sub2.request(1);
+            expectNextElement(sub2, z);
+          }
+          if (totalRequests == 3) {
+            expectRequest();
+          }
+
+          // to avoid error messages during test harness shutdown
+          sendCompletion();
+          sub1.expectCompletion(env.defaultTimeoutMillis());
+          sub2.expectCompletion(env.defaultTimeoutMillis());
+
+          env.verifyNoAsyncErrorsNoDelay();
+        }};
+      }
+    });
+  }
+
+  /////////////////////// TEST INFRASTRUCTURE //////////////////////
+
+  public void notVerified() {
+    publisherVerification.notVerified();
+  }
+
+  public void notVerified(String message) {
+    publisherVerification.notVerified(message);
+  }
+
+  /**
+   * Test for feature that REQUIRES multiple subscribers to be supported by Publisher.
+   */
+  public void optionalMultipleSubscribersTest(long requiredSubscribersSupport, Function<Long, TestSetup> body) throws Throwable {
+    if (requiredSubscribersSupport > maxSupportedSubscribers())
+      notVerified(String.format("The Publisher under test only supports %d subscribers, while this test requires at least %d to run.",
+                                maxSupportedSubscribers(), requiredSubscribersSupport));
+    else body.apply(requiredSubscribersSupport);
+  }
+
+  public abstract class TestSetup extends ManualPublisher<T> {
+    final private ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+    private Set<T> seenTees = new HashSet<T>();
+
+    final Processor<T, T> processor;
+
+    public TestSetup(TestEnvironment env, int testBufferSize) throws InterruptedException {
+      super(env);
+      tees = env.newManualSubscriber(createHelperPublisher(Long.MAX_VALUE));
+      processor = createIdentityProcessor(testBufferSize);
+      subscribe(processor);
+    }
+
+    public ManualSubscriber<T> newSubscriber() throws InterruptedException {
+      return env.newManualSubscriber(processor);
+    }
+
+    public T nextT() throws InterruptedException {
+      final T t = tees.requestNextElement();
+      if (seenTees.contains(t)) {
+        env.flop(String.format("Helper publisher illegally produced the same element %s twice", t));
+      }
+      seenTees.add(t);
+      return t;
+    }
+
+    public void expectNextElement(ManualSubscriber<T> sub, T expected) throws InterruptedException {
+      final T elem = sub.nextElement(String.format("timeout while awaiting %s", expected));
+      if (!elem.equals(expected)) {
+        env.flop(String.format("Received `onNext(%s)` on downstream but expected `onNext(%s)`", elem, expected));
+      }
+    }
+
+    public void expectNextElement(ManualSubscriber<T> sub, T expected, String errorMessageAddendum) throws InterruptedException {
+      final T elem = sub.nextElement(String.format("timeout while awaiting %s. %s", expected, errorMessageAddendum));
+      if (!elem.equals(expected)) {
+        env.flop(String.format("Received `onNext(%s)` on downstream but expected `onNext(%s)`", elem, expected));
+      }
+    }
+
+    public T sendNextTFromUpstream() throws InterruptedException {
+      final T x = nextT();
+      sendNext(x);
+      return x;
+    }
+  }
+
+  public class ManualSubscriberWithErrorCollection<A> extends ManualSubscriberWithSubscriptionSupport<A> {
+    Promise<Throwable> error;
+
+    public ManualSubscriberWithErrorCollection(TestEnvironment env) {
+      super(env);
+      error = new Promise<Throwable>(env);
+    }
+
+    @Override
+    public void onError(Throwable cause) {
+      error.complete(cause);
+    }
+
+    public void expectError(Throwable cause) throws InterruptedException {
+      expectError(cause, env.defaultTimeoutMillis());
+    }
+
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    public void expectError(Throwable cause, long timeoutMillis) throws InterruptedException {
+      error.expectCompletion(timeoutMillis, "Did not receive expected error on downstream");
+      if (!cause.equals(error.value())) {
+        env.flop(String.format("Expected error %s but got %s", cause, error.value()));
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/PublisherVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.tck.TestEnvironment.BlackholeSubscriberWithSubscriptionSupport;
+import org.reactivestreams.tck.TestEnvironment.Latch;
+import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+import org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport;
+import org.reactivestreams.tck.flow.support.Function;
+import org.reactivestreams.tck.flow.support.Optional;
+import org.reactivestreams.tck.flow.support.PublisherVerificationRules;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.lang.Override;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Provides tests for verifying {@code Publisher} specification rules.
+ *
+ * @see org.reactivestreams.Publisher
+ */
+public abstract class PublisherVerification<T> implements PublisherVerificationRules {
+
+  private static final String PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV = "PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS";
+  private static final long DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS = 300L;
+
+  private final TestEnvironment env;
+
+  /**
+   * The amount of time after which a cancelled Subscriber reference should be dropped.
+   * See Rule 3.13 for details.
+   */
+  private final long publisherReferenceGCTimeoutMillis;
+
+  /**
+   * Constructs a new verification class using the given env and configuration.
+   *
+   * @param publisherReferenceGCTimeoutMillis used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+   */
+  public PublisherVerification(TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+    this.env = env;
+    this.publisherReferenceGCTimeoutMillis = publisherReferenceGCTimeoutMillis;
+  }
+
+  /**
+   * Constructs a new verification class using the given env and configuration.
+   *
+   * The value for {@code publisherReferenceGCTimeoutMillis} will be obtained by using {@link PublisherVerification#envPublisherReferenceGCTimeoutMillis()}.
+   */
+  public PublisherVerification(TestEnvironment env) {
+    this.env = env;
+    this.publisherReferenceGCTimeoutMillis = envPublisherReferenceGCTimeoutMillis();
+  }
+
+  /**
+   * Tries to parse the env variable {@code PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS} as long and returns the value if present,
+   * OR its default value ({@link PublisherVerification#DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS}).
+   *
+   * This value is used to determine after how much time a reference to a Subscriber should be already dropped by the Publisher.
+   *
+   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+   */
+  public static long envPublisherReferenceGCTimeoutMillis() {
+    final String envMillis = System.getenv(PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV);
+    if (envMillis == null) return DEFAULT_PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS;
+    else try {
+      return Long.parseLong(envMillis);
+    } catch (NumberFormatException ex) {
+      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", PUBLISHER_REFERENCE_GC_TIMEOUT_MILLIS_ENV, envMillis), ex);
+    }
+  }
+
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a Publisher for a stream with exactly the given number of elements.
+   * If `elements` is `Long.MAX_VALUE` the produced stream must be infinite.
+   */
+  public abstract Publisher<T> createPublisher(long elements);
+
+  /**
+   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+   *
+   * The expected behaviour of the {@link Publisher} returned by this method is hand out a subscription,
+   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+   *
+   * If you ignore these additional tests, return {@code null} from this method.
+   */
+  public abstract Publisher<T> createFailedPublisher();
+
+
+  /**
+   * Override and return lower value if your Publisher is only able to produce a known number of elements.
+   * For example, if it is designed to return at-most-one element, return {@code 1} from this method.
+   *
+   * Defaults to {@code Long.MAX_VALUE - 1}, meaning that the Publisher can be produce a huge but NOT an unbounded number of elements.
+   *
+   * To mark your Publisher will *never* signal an {@code onComplete} override this method and return {@code Long.MAX_VALUE},
+   * which will result in *skipping all tests which require an onComplete to be triggered* (!).
+   */
+  public long maxElementsFromPublisher() {
+    return Long.MAX_VALUE - 1;
+  }
+
+  /**
+   * Override and return {@code true} in order to skip executing tests marked as {@code Stochastic}.
+   * Stochastic in this case means that the Rule is impossible or infeasible to deterministically verify—
+   * usually this means that this test case can yield false positives ("be green") even if for some case,
+   * the given implementation may violate the tested behaviour.
+   */
+  public boolean skipStochasticTests() {
+    return false;
+  }
+
+  /**
+   * In order to verify rule 3.3 of the reactive streams spec, this number will be used to check if a
+   * {@code Subscription} actually solves the "unbounded recursion" problem by not allowing the number of
+   * recursive calls to exceed the number returned by this method.
+   *
+   * @see <a href="https://github.com/reactive-streams/reactive-streams-jvm#3.3">reactive streams spec, rule 3.3</a>
+   * @see PublisherVerification#required_spec303_mustNotAllowUnboundedRecursion()
+   */
+  public long boundedDepthOfOnNextAndRequestRecursion() {
+    return 1;
+  }
+
+  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+
+  @BeforeMethod
+  public void setUp() throws Exception {
+    env.clearAsyncErrors();
+  }
+
+  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+
+  @Override @Test
+  public void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable {
+    activePublisherTest(1, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws InterruptedException {
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced no elements", pub));
+        sub.requestEndOfStream();
+      }
+
+      Optional<T> requestNextElementOrEndOfStream(Publisher<T> pub, ManualSubscriber<T> sub) throws InterruptedException {
+        return sub.requestNextElementOrEndOfStream(String.format("Timeout while waiting for next element from Publisher %s", pub));
+      }
+
+    });
+  }
+
+  @Override @Test
+  public void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable {
+    activePublisherTest(3, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws InterruptedException {
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced no elements", pub));
+        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced only 1 element", pub));
+        assertTrue(requestNextElementOrEndOfStream(pub, sub).isDefined(), String.format("Publisher %s produced only 2 elements", pub));
+        sub.requestEndOfStream();
+      }
+
+      Optional<T> requestNextElementOrEndOfStream(Publisher<T> pub, ManualSubscriber<T> sub) throws InterruptedException {
+        return sub.requestNextElementOrEndOfStream(String.format("Timeout while waiting for next element from Publisher %s", pub));
+      }
+
+    });
+  }
+
+  @Override @Test
+  public void required_validate_maxElementsFromPublisher() throws Exception {
+    assertTrue(maxElementsFromPublisher() >= 0, "maxElementsFromPublisher MUST return a number >= 0");
+  }
+
+  @Override @Test
+  public void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception {
+    assertTrue(boundedDepthOfOnNextAndRequestRecursion() >= 1, "boundedDepthOfOnNextAndRequestRecursion must return a number >= 1");
+  }
+
+
+  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+
+  @Override @Test
+  public void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable {
+    activePublisherTest(5, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws InterruptedException {
+
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        try {
+            sub.expectNone(String.format("Publisher %s produced value before the first `request`: ", pub));
+            sub.request(1);
+            sub.nextElement(String.format("Publisher %s produced no element after first `request`", pub));
+            sub.expectNone(String.format("Publisher %s produced unrequested: ", pub));
+
+            sub.request(1);
+            sub.request(2);
+            sub.nextElements(3, env.defaultTimeoutMillis(), String.format("Publisher %s produced less than 3 elements after two respective `request` calls", pub));
+
+            sub.expectNone(String.format("Publisher %sproduced unrequested ", pub));
+        } finally {
+            sub.cancel();
+        }
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable {
+    final int elements = 3;
+    final int requested = 10;
+
+    activePublisherTest(elements, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.request(requested);
+        sub.nextElements(elements);
+        sub.expectCompletion();
+      }
+    });
+  }
+
+  @Override @Test
+  public void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable {
+    final int iterations = 100;
+    final int elements = 10;
+
+    stochasticTest(iterations, new Function<Integer, Void>() {
+      @Override
+      public Void apply(final Integer runNumber) throws Throwable {
+        activePublisherTest(elements, true, new PublisherTestRun<T>() {
+          @Override
+          public void run(Publisher<T> pub) throws Throwable {
+            final Latch completionLatch = new Latch(env);
+
+            final AtomicInteger gotElements = new AtomicInteger(0);
+            pub.subscribe(new Subscriber<T>() {
+              private Subscription subs;
+
+              private ConcurrentAccessBarrier concurrentAccessBarrier = new ConcurrentAccessBarrier();
+
+              /**
+               * Concept wise very similar to a {@link org.reactivestreams.tck.TestEnvironment.Latch}, serves to protect
+               * a critical section from concurrent access, with the added benefit of Thread tracking and same-thread-access awareness.
+               *
+               * Since a <i>Synchronous</i> Publisher may choose to synchronously (using the same {@link Thread}) call
+               * {@code onNext} directly from either {@code subscribe} or {@code request} a plain Latch is not enough
+               * to verify concurrent access safety - one needs to track if the caller is not still using the calling thread
+               * to enter subsequent critical sections ("nesting" them effectively).
+               */
+              final class ConcurrentAccessBarrier {
+                private AtomicReference<Thread> currentlySignallingThread = new AtomicReference<Thread>(null);
+                private volatile String previousSignal = null;
+
+                public void enterSignal(String signalName) {
+                  if((!currentlySignallingThread.compareAndSet(null, Thread.currentThread())) && !isSynchronousSignal()) {
+                    env.flop(String.format(
+                      "Illegal concurrent access detected (entering critical section)! " +
+                        "%s emited %s signal, before %s finished its %s signal.",
+                        Thread.currentThread(), signalName, currentlySignallingThread.get(), previousSignal));
+                  }
+                  this.previousSignal = signalName;
+                }
+
+                public void leaveSignal(String signalName) {
+                  currentlySignallingThread.set(null);
+                  this.previousSignal = signalName;
+                }
+
+                private boolean isSynchronousSignal() {
+                  return (previousSignal != null) && Thread.currentThread().equals(currentlySignallingThread.get());
+                }
+
+              }
+
+              @Override
+              public void onSubscribe(Subscription s) {
+                final String signal = "onSubscribe()";
+                concurrentAccessBarrier.enterSignal(signal);
+
+                subs = s;
+                subs.request(1);
+
+                concurrentAccessBarrier.leaveSignal(signal);
+              }
+
+              @Override
+              public void onNext(T ignore) {
+                final String signal = String.format("onNext(%s)", ignore);
+                concurrentAccessBarrier.enterSignal(signal);
+
+                if (gotElements.incrementAndGet() <= elements) // requesting one more than we know are in the stream (some Publishers need this)
+                  subs.request(1);
+
+                concurrentAccessBarrier.leaveSignal(signal);
+              }
+
+              @Override
+              public void onError(Throwable t) {
+                final String signal = String.format("onError(%s)", t.getMessage());
+                concurrentAccessBarrier.enterSignal(signal);
+
+                // ignore value
+
+                concurrentAccessBarrier.leaveSignal(signal);
+              }
+
+              @Override
+              public void onComplete() {
+                final String signal = "onComplete()";
+                concurrentAccessBarrier.enterSignal(signal);
+
+                // entering for completeness
+
+                concurrentAccessBarrier.leaveSignal(signal);
+                completionLatch.close();
+              }
+            });
+
+            completionLatch.expectClose(
+              elements * env.defaultTimeoutMillis(),
+              String.format("Failed in iteration %d of %d. Expected completion signal after signalling %d elements (signalled %d), yet did not receive it",
+                            runNumber, iterations, elements, gotElements.get()));
+          }
+        });
+        return null;
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable {
+    try {
+      whenHasErrorPublisherTest(new PublisherTestRun<T>() {
+        @Override
+        public void run(final Publisher<T> pub) throws InterruptedException {
+          final Latch onErrorlatch = new Latch(env);
+          final Latch onSubscribeLatch = new Latch(env);
+          pub.subscribe(new TestEnvironment.TestSubscriber<T>(env) {
+            @Override
+            public void onSubscribe(Subscription subs) {
+              onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+              onSubscribeLatch.close();
+            }
+            @Override
+            public void onError(Throwable cause) {
+              onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+              onErrorlatch.assertOpen(String.format("Error-state Publisher %s called `onError` twice on new Subscriber", pub));
+              onErrorlatch.close();
+            }
+          });
+
+          onSubscribeLatch.expectClose("Should have received onSubscribe");
+          onErrorlatch.expectClose(String.format("Error-state Publisher %s did not call `onError` on new Subscriber", pub));
+
+          env.verifyNoAsyncErrors();
+          }
+      });
+    } catch (SkipException se) {
+      throw se;
+    } catch (Throwable ex) {
+      // we also want to catch AssertionErrors and anything the publisher may have thrown inside subscribe
+      // which was wrong of him - he should have signalled on error using onError
+      throw new RuntimeException(String.format("Publisher threw exception (%s) instead of signalling error via onError!", ex.getMessage()), ex);
+    }
+  }
+
+  @Override @Test
+  public void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable {
+    activePublisherTest(3, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.requestNextElement();
+        sub.requestNextElement();
+        sub.requestNextElement();
+        sub.requestEndOfStream();
+        sub.expectNone();
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable {
+    optionalActivePublisherTest(0, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.request(1);
+        sub.expectCompletion();
+        sub.expectNone();
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable {
+    notVerified(); // not really testable without more control over the Publisher
+  }
+
+  @Override @Test
+  public void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable {
+    activePublisherTest(1, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.request(10);
+        sub.nextElement();
+        sub.expectCompletion();
+
+        sub.request(10);
+        sub.expectNone();
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable {
+    notVerified(); // can we meaningfully test this, without more control over the publisher?
+  }
+
+  @Override @Test
+  public void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable {
+    notVerified(); // can we meaningfully test this?
+  }
+
+  @Override @Test
+  public void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable {
+    notVerified(); // can we meaningfully test this?
+  }
+
+  @Override @Test
+  public void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable {
+    activePublisherTest(0, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        try {
+            pub.subscribe(null);
+            env.flop("Publisher did not throw a NullPointerException when given a null Subscribe in subscribe");
+        } catch (NullPointerException ignored) {
+          // valid behaviour
+        }
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable {
+    activePublisherTest(0, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final Latch onSubscribeLatch = new Latch(env);
+        final AtomicReference<Subscription> cancel = new AtomicReference<Subscription>();
+        try {
+          pub.subscribe(new Subscriber<T>() {
+            @Override
+            public void onError(Throwable cause) {
+              onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+            }
+
+            @Override
+            public void onSubscribe(Subscription subs) {
+              cancel.set(subs);
+              onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+              onSubscribeLatch.close();
+            }
+
+            @Override
+            public void onNext(T elem) {
+              onSubscribeLatch.assertClosed("onSubscribe should be called prior to onNext always");
+            }
+
+            @Override
+            public void onComplete() {
+              onSubscribeLatch.assertClosed("onSubscribe should be called prior to onComplete always");
+            }
+          });
+          onSubscribeLatch.expectClose("Should have received onSubscribe");
+          env.verifyNoAsyncErrorsNoDelay();
+        } finally {
+          Subscription s = cancel.getAndSet(null);
+          if (s != null) {
+            s.cancel();
+          }
+        }
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable {
+    whenHasErrorPublisherTest(new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final Latch onErrorLatch = new Latch(env);
+        final Latch onSubscribeLatch = new Latch(env);
+        ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+          @Override
+          public void onError(Throwable cause) {
+            onSubscribeLatch.assertClosed("onSubscribe should be called prior to onError always");
+            onErrorLatch.assertOpen("Only one onError call expected");
+            onErrorLatch.close();
+          }
+
+          @Override
+          public void onSubscribe(Subscription subs) {
+            onSubscribeLatch.assertOpen("Only one onSubscribe call expected");
+            onSubscribeLatch.close();
+          }
+        };
+        pub.subscribe(sub);
+        onSubscribeLatch.expectClose("Should have received onSubscribe");
+        onErrorLatch.expectClose("Should have received onError");
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable {
+    notVerified(); // can we meaningfully test this?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#1.11
+  @Override @Test
+  public void optional_spec111_maySupportMultiSubscribe() throws Throwable {
+    optionalActivePublisherTest(1, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+
+        try {
+          env.verifyNoAsyncErrors();
+        } finally {
+          try {
+            sub1.cancel();
+          } finally {
+            sub2.cancel();
+          }
+        }
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec111_registeredSubscribersMustReceiveOnNextOrOnCompleteSignals() throws Throwable {
+    optionalActivePublisherTest(1, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+        // Since we're testing the case when the Publisher DOES support the optional multi-subscribers scenario,
+        // and decides if it handles them uni-cast or multi-cast, we don't know which subscriber will receive an
+        // onNext (and optional onComplete) signal(s) and which just onComplete signal.
+        // Plus, even if subscription assumed to be unicast, it's implementation choice, which one will be signalled
+        // with onNext.
+        sub1.requestNextElementOrEndOfStream();
+        sub2.requestNextElementOrEndOfStream();
+        try {
+            env.verifyNoAsyncErrors();
+        } finally {
+            try {
+                sub1.cancel();
+            } finally {
+                sub2.cancel();
+            }
+        }
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable {
+    optionalActivePublisherTest(5, true, new PublisherTestRun<T>() { // This test is skipped if the publisher is unbounded (never sends onComplete)
+      @Override
+      public void run(Publisher<T> pub) throws InterruptedException {
+        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+
+        sub1.request(1);
+        T x1 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+        sub2.request(2);
+        List<T> y1 = sub2.nextElements(2, String.format("Publisher %s did not produce the requested 2 elements on 2nd subscriber", pub));
+        sub1.request(1);
+        T x2 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+        sub3.request(3);
+        List<T> z1 = sub3.nextElements(3, String.format("Publisher %s did not produce the requested 3 elements on 3rd subscriber", pub));
+        sub3.request(1);
+        T z2 = sub3.nextElement(String.format("Publisher %s did not produce the requested 1 element on 3rd subscriber", pub));
+        sub3.request(1);
+        T z3 = sub3.nextElement(String.format("Publisher %s did not produce the requested 1 element on 3rd subscriber", pub));
+        sub3.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 3rd subscriber", pub));
+        sub2.request(3);
+        List<T> y2 = sub2.nextElements(3, String.format("Publisher %s did not produce the requested 3 elements on 2nd subscriber", pub));
+        sub2.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 2nd subscriber", pub));
+        sub1.request(2);
+        List<T> x3 = sub1.nextElements(2, String.format("Publisher %s did not produce the requested 2 elements on 1st subscriber", pub));
+        sub1.request(1);
+        T x4 = sub1.nextElement(String.format("Publisher %s did not produce the requested 1 element on 1st subscriber", pub));
+        sub1.requestEndOfStream(String.format("Publisher %s did not complete the stream as expected on 1st subscriber", pub));
+
+        @SuppressWarnings("unchecked")
+        List<T> r = new ArrayList<T>(Arrays.asList(x1, x2));
+        r.addAll(x3);
+        r.addAll(Collections.singleton(x4));
+
+        List<T> check1 = new ArrayList<T>(y1);
+        check1.addAll(y2);
+
+        //noinspection unchecked
+        List<T> check2 = new ArrayList<T>(z1);
+        check2.add(z2);
+        check2.add(z3);
+
+        assertEquals(r, check1, String.format("Publisher %s did not produce the same element sequence for subscribers 1 and 2", pub));
+        assertEquals(r, check2, String.format("Publisher %s did not produce the same element sequence for subscribers 1 and 3", pub));
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable {
+    optionalActivePublisherTest(3, false, new PublisherTestRun<T>() { // This test is skipped if the publisher cannot produce enough elements
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+
+        List<T> received1 = new ArrayList<T>();
+        List<T> received2 = new ArrayList<T>();
+        List<T> received3 = new ArrayList<T>();
+
+        // 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...
+        // edgy edge case?
+        sub1.request(4);
+        sub2.request(4);
+        sub3.request(4);
+
+        received1.addAll(sub1.nextElements(3));
+        received2.addAll(sub2.nextElements(3));
+        received3.addAll(sub3.nextElements(3));
+
+        // NOTE: can't check completion, the Publisher may not be able to signal it
+        //       a similar test *with* completion checking is implemented
+
+        assertEquals(received1, received2, String.format("Expected elements to be signaled in the same sequence to 1st and 2nd subscribers"));
+        assertEquals(received2, received3, String.format("Expected elements to be signaled in the same sequence to 2nd and 3rd subscribers"));
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable {
+    optionalActivePublisherTest(3, true, new PublisherTestRun<T>() { // This test is skipped if the publisher is unbounded (never sends onComplete)
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub1 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub2 = env.newManualSubscriber(pub);
+        ManualSubscriber<T> sub3 = env.newManualSubscriber(pub);
+
+        List<T> received1 = new ArrayList<T>();
+        List<T> received2 = new ArrayList<T>();
+        List<T> received3 = new ArrayList<T>();
+
+        // 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...
+        // edgy edge case?
+        sub1.request(4);
+        sub2.request(4);
+        sub3.request(4);
+
+        received1.addAll(sub1.nextElements(3));
+        received2.addAll(sub2.nextElements(3));
+        received3.addAll(sub3.nextElements(3));
+
+        sub1.expectCompletion();
+        sub2.expectCompletion();
+        sub3.expectCompletion();
+
+        assertEquals(received1, received2, String.format("Expected elements to be signaled in the same sequence to 1st and 2nd subscribers"));
+        assertEquals(received2, received3, String.format("Expected elements to be signaled in the same sequence to 2nd and 3rd subscribers"));
+      }
+    });
+  }
+
+  ///////////////////// SUBSCRIPTION TESTS //////////////////////////////////
+
+  @Override @Test
+  public void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable {
+    activePublisherTest(6, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub = new ManualSubscriber<T>(env) {
+          @Override
+          public void onSubscribe(Subscription subs) {
+            this.subscription.completeImmediatly(subs);
+
+            subs.request(1);
+            subs.request(1);
+            subs.request(1);
+          }
+
+          @Override
+          public void onNext(T element) {
+            Subscription subs = this.subscription.value();
+            subs.request(1);
+          }
+        };
+
+        env.subscribe(pub, sub);
+
+        env.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable {
+    final long oneMoreThanBoundedLimit = boundedDepthOfOnNextAndRequestRecursion() + 1;
+
+    activePublisherTest(oneMoreThanBoundedLimit, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final ThreadLocal<Long> stackDepthCounter = new ThreadLocal<Long>() {
+          @Override
+          protected Long initialValue() {
+            return 0L;
+          }
+        };
+
+        final Latch runCompleted = new Latch(env);
+
+        final ManualSubscriber<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+          // counts the number of signals received, used to break out from possibly infinite request/onNext loops
+          long signalsReceived = 0L;
+
+          @Override
+          public void onNext(T element) {
+            // NOT calling super.onNext as this test only cares about stack depths, not the actual values of elements
+            // which also simplifies this test as we do not have to drain the test buffer, which would otherwise be in danger of overflowing
+
+            signalsReceived += 1;
+            stackDepthCounter.set(stackDepthCounter.get() + 1);
+            if (env.debugEnabled()) {
+              env.debug(String.format("%s(recursion depth: %d)::onNext(%s)", this, stackDepthCounter.get(), element));
+            }
+
+            final long callsUntilNow = stackDepthCounter.get();
+            if (callsUntilNow > boundedDepthOfOnNextAndRequestRecursion()) {
+              env.flop(String.format("Got %d onNext calls within thread: %s, yet expected recursive bound was %d",
+                                     callsUntilNow, Thread.currentThread(), boundedDepthOfOnNextAndRequestRecursion()));
+
+              // stop the recursive call chain
+              runCompleted.close();
+              return;
+            } else if (signalsReceived >= oneMoreThanBoundedLimit) {
+              // since max number of signals reached, and recursion depth not exceeded, we judge this as a success and
+              // stop the recursive call chain
+              runCompleted.close();
+              return;
+            }
+
+            // request more right away, the Publisher must break the recursion
+            subscription.value().request(1);
+
+            stackDepthCounter.set(stackDepthCounter.get() - 1);
+          }
+
+          @Override
+          public void onComplete() {
+            super.onComplete();
+            runCompleted.close();
+          }
+
+          @Override
+          public void onError(Throwable cause) {
+            super.onError(cause);
+            runCompleted.close();
+          }
+        };
+
+        try {
+          env.subscribe(pub, sub);
+
+          sub.request(1); // kick-off the `request -> onNext -> request -> onNext -> ...`
+
+          final String msg = String.format("Unable to validate call stack depth safety, " +
+                                               "awaited at-most %s signals (`maxOnNextSignalsInRecursionTest()`) or completion",
+                                           oneMoreThanBoundedLimit);
+          runCompleted.expectClose(env.defaultTimeoutMillis(), msg);
+          env.verifyNoAsyncErrorsNoDelay();
+        } finally {
+          // since the request/onNext recursive calls may keep the publisher running "forever",
+          // we MUST cancel it manually before exiting this test case
+          sub.cancel();
+        }
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec305_cancelMustNotSynchronouslyPerformHeavyComputation() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable {
+    activePublisherTest(3, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+
+        // override ManualSubscriberWithSubscriptionSupport#cancel because by default a ManualSubscriber will drop the
+        // subscription once it's cancelled (as expected).
+        // In this test however it must keep the cancelled Subscription and keep issuing `request(long)` to it.
+        ManualSubscriber<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(env) {
+          @Override
+          public void cancel() {
+            if (subscription.isCompleted()) {
+              subscription.value().cancel();
+            } else {
+              env.flop("Cannot cancel a subscription before having received it");
+            }
+          }
+        };
+
+        env.subscribe(pub, sub);
+
+        sub.cancel();
+        sub.request(1);
+        sub.request(1);
+        sub.request(1);
+
+        sub.expectNone();
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable {
+    activePublisherTest(1, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+
+        // leak the Subscription
+        final Subscription subs = sub.subscription.value();
+
+        subs.cancel();
+        subs.cancel();
+        subs.cancel();
+
+        sub.expectNone();
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable {
+    activePublisherTest(10, false, new PublisherTestRun<T>() {
+      @Override public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.request(0);
+        sub.expectError(IllegalArgumentException.class);
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable {
+    activePublisherTest(10, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        final Random r = new Random();
+        sub.request(-r.nextInt(Integer.MAX_VALUE) - 1);
+        // we do require implementations to mention the rule number at the very least, or mentioning that the non-negative request is the problem
+        sub.expectError(IllegalArgumentException.class);
+      }
+    });
+  }
+
+  @Override @Test
+  public void optional_spec309_requestNegativeNumberMaySignalIllegalArgumentExceptionWithSpecificMessage() throws Throwable {
+    optionalActivePublisherTest(10, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        final Random r = new Random();
+        sub.request(-r.nextInt(Integer.MAX_VALUE) - 1);
+        // we do require implementations to mention the rule number at the very least, or mentioning that the non-negative request is the problem
+        sub.expectErrorWithMessage(IllegalArgumentException.class, Arrays.asList("3.9", "non-positive subscription request", "negative subscription request"));
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable {
+    // the publisher is able to signal more elements than the subscriber will be requesting in total
+    final int publisherElements = 20;
+
+    final int demand1 = 10;
+    final int demand2 = 5;
+    final int totalDemand = demand1 + demand2;
+
+    activePublisherTest(publisherElements, false, new PublisherTestRun<T>() {
+      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+      public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+
+        sub.request(demand1);
+        sub.request(demand2);
+
+        /*
+          NOTE: The order of the nextElement/cancel calls below is very important (!)
+
+          If this ordering was reversed, given an asynchronous publisher,
+          the following scenario would be *legal* and would break this test:
+
+          > AsyncPublisher receives request(10) - it does not emit data right away, it's asynchronous
+          > AsyncPublisher receives request(5) - demand is now 15
+          ! AsyncPublisher didn't emit any onNext yet (!)
+          > AsyncPublisher receives cancel() - handles it right away, by "stopping itself" for example
+          ! cancel was handled hefore the AsyncPublisher ever got the chance to emit data
+          ! the subscriber ends up never receiving even one element - the test is stuck (and fails, even on valid Publisher)
+
+          Which is why we must first expect an element, and then cancel, once the producing is "running".
+         */
+        sub.nextElement();
+        sub.cancel();
+
+        int onNextsSignalled = 1;
+
+        boolean stillBeingSignalled;
+        do {
+          // put asyncError if onNext signal received
+          sub.expectNone();
+          Throwable error = env.dropAsyncError();
+
+          if (error == null) {
+            stillBeingSignalled = false;
+          } else {
+            onNextsSignalled += 1;
+            stillBeingSignalled = true;
+          }
+
+          // if the Publisher tries to emit more elements than was requested (and/or ignores cancellation) this will throw
+          assertTrue(onNextsSignalled <= totalDemand,
+                     String.format("Publisher signalled [%d] elements, which is more than the signalled demand: %d",
+                                   onNextsSignalled, totalDemand));
+
+        } while (stillBeingSignalled);
+      }
+    });
+
+    env.verifyNoAsyncErrorsNoDelay();
+  }
+
+  @Override @Test
+  public void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable {
+    final ReferenceQueue<ManualSubscriber<T>> queue = new ReferenceQueue<ManualSubscriber<T>>();
+
+    final Function<Publisher<T>, WeakReference<ManualSubscriber<T>>> run = new Function<Publisher<T>, WeakReference<ManualSubscriber<T>>>() {
+      @Override
+      public WeakReference<ManualSubscriber<T>> apply(Publisher<T> pub) throws Exception {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        final WeakReference<ManualSubscriber<T>> ref = new WeakReference<ManualSubscriber<T>>(sub, queue);
+
+        sub.request(1);
+        sub.nextElement();
+        sub.cancel();
+
+        return ref;
+      }
+    };
+
+    activePublisherTest(3, false, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final WeakReference<ManualSubscriber<T>> ref = run.apply(pub);
+
+        // cancel may be run asynchronously so we add a sleep before running the GC
+        // to "resolve" the race
+        Thread.sleep(publisherReferenceGCTimeoutMillis);
+        System.gc();
+
+        if (!ref.equals(queue.remove(100))) {
+          env.flop(String.format("Publisher %s did not drop reference to test subscriber after subscription cancellation", pub));
+        }
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable {
+    final int totalElements = 3;
+
+    activePublisherTest(totalElements, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.request(Long.MAX_VALUE);
+
+        sub.nextElements(totalElements);
+        sub.expectCompletion();
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable {
+    final int totalElements = 3;
+
+    activePublisherTest(totalElements, true, new PublisherTestRun<T>() {
+      @Override
+      public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriber<T> sub = env.newManualSubscriber(pub);
+        sub.request(Long.MAX_VALUE / 2); // pending = Long.MAX_VALUE / 2
+        sub.request(Long.MAX_VALUE / 2); // pending = Long.MAX_VALUE - 1
+        sub.request(1); // pending = Long.MAX_VALUE
+
+        sub.nextElements(totalElements);
+        sub.expectCompletion();
+
+        try {
+          env.verifyNoAsyncErrorsNoDelay();
+        } finally {
+          sub.cancel();
+        }
+
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable {
+    activePublisherTest(Integer.MAX_VALUE, false, new PublisherTestRun<T>() {
+      @Override public void run(Publisher<T> pub) throws Throwable {
+        final ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(env) {
+           // arbitrarily set limit on nuber of request calls signalled, we expect overflow after already 2 calls,
+           // so 10 is relatively high and safe even if arbitrarily chosen
+          int callsCounter = 10;
+
+          @Override
+          public void onNext(T element) {
+            if (env.debugEnabled()) {
+              env.debug(String.format("%s::onNext(%s)", this, element));
+            }
+            if (subscription.isCompleted()) {
+              if (callsCounter > 0) {
+                subscription.value().request(Long.MAX_VALUE - 1);
+                callsCounter--;
+              } else {
+                  subscription.value().cancel();
+              }
+            } else {
+              env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+            }
+          }
+        };
+        env.subscribe(pub, sub, env.defaultTimeoutMillis());
+
+        // eventually triggers `onNext`, which will then trigger up to `callsCounter` times `request(Long.MAX_VALUE - 1)`
+        // we're pretty sure to overflow from those
+        sub.request(1);
+
+        // no onError should be signalled
+        try {
+          env.verifyNoAsyncErrors();
+        } finally {
+          sub.cancel();
+        }
+      }
+    });
+  }
+
+  ///////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+
+  ///////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+
+  public interface PublisherTestRun<T> {
+    public void run(Publisher<T> pub) throws Throwable;
+  }
+
+  /**
+   * Test for feature that SHOULD/MUST be implemented, using a live publisher.
+   *
+   * @param elements the number of elements the Publisher under test  must be able to emit to run this test
+   * @param completionSignalRequired true if an {@code onComplete} signal is required by this test to run.
+   *                                 If the tested Publisher is unable to signal completion, tests requireing onComplete signals will be skipped.
+   *                                 To signal if your Publisher is able to signal completion see {@link PublisherVerification#maxElementsFromPublisher()}.
+   */
+  public void activePublisherTest(long elements, boolean completionSignalRequired, PublisherTestRun<T> body) throws Throwable {
+    if (elements > maxElementsFromPublisher()) {
+      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()));
+    } else if (completionSignalRequired && maxElementsFromPublisher() == Long.MAX_VALUE) {
+      throw new SkipException("Unable to run this test, as it requires an onComplete signal, " +
+                                "which this Publisher is unable to provide (as signalled by returning Long.MAX_VALUE from `maxElementsFromPublisher()`)");
+    } else {
+      Publisher<T> pub = createPublisher(elements);
+      body.run(pub);
+      env.verifyNoAsyncErrorsNoDelay();
+    }
+  }
+
+  /**
+   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+   *
+   * @param elements the number of elements the Publisher under test  must be able to emit to run this test
+   * @param completionSignalRequired true if an {@code onComplete} signal is required by this test to run.
+   *                                 If the tested Publisher is unable to signal completion, tests requireing onComplete signals will be skipped.
+   *                                 To signal if your Publisher is able to signal completion see {@link PublisherVerification#maxElementsFromPublisher()}.
+   */
+  public void optionalActivePublisherTest(long elements, boolean completionSignalRequired, PublisherTestRun<T> body) throws Throwable {
+    if (elements > maxElementsFromPublisher()) {
+      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()));
+    } else if (completionSignalRequired && maxElementsFromPublisher() == Long.MAX_VALUE) {
+      throw new SkipException("Unable to run this test, as it requires an onComplete signal, " +
+                                "which this Publisher is unable to provide (as signalled by returning Long.MAX_VALUE from `maxElementsFromPublisher()`)");
+    } else {
+
+      final Publisher<T> pub = createPublisher(elements);
+      final String skipMessage = "Skipped because tested publisher does NOT implement this OPTIONAL requirement.";
+
+      try {
+        potentiallyPendingTest(pub, body);
+      } catch (Exception ex) {
+        notVerified(skipMessage);
+      } catch (AssertionError ex) {
+        notVerified(skipMessage + " Reason for skipping was: " + ex.getMessage());
+      }
+    }
+  }
+
+  public static final String SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE =
+    "Skipping because no error state Publisher provided, and the test requires it. " +
+          "Please implement PublisherVerification#createFailedPublisher to run this test.";
+
+  public static final String SKIPPING_OPTIONAL_TEST_FAILED =
+    "Skipping, because provided Publisher does not pass this *additional* verification.";
+  /**
+   * Additional test for Publisher in error state
+   */
+  public void whenHasErrorPublisherTest(PublisherTestRun<T> body) throws Throwable {
+    potentiallyPendingTest(createFailedPublisher(), body, SKIPPING_NO_ERROR_PUBLISHER_AVAILABLE);
+  }
+
+  public void potentiallyPendingTest(Publisher<T> pub, PublisherTestRun<T> body) throws Throwable {
+    potentiallyPendingTest(pub, body, SKIPPING_OPTIONAL_TEST_FAILED);
+  }
+
+  public void potentiallyPendingTest(Publisher<T> pub, PublisherTestRun<T> body, String message) throws Throwable {
+    if (pub != null) {
+      body.run(pub);
+    } else {
+      throw new SkipException(message);
+    }
+  }
+
+  /**
+   * Executes a given test body {@code n} times.
+   * All the test runs must pass in order for the stochastic test to pass.
+   */
+  public void stochasticTest(int n, Function<Integer, Void> body) throws Throwable {
+    if (skipStochasticTests()) {
+      notVerified("Skipping @Stochastic test because `skipStochasticTests()` returned `true`!");
+    }
+
+    for (int i = 0; i < n; i++) {
+      body.apply(i);
+    }
+  }
+
+  public void notVerified() {
+    throw new SkipException("Not verified by this TCK.");
+  }
+
+  /**
+   * Return this value from {@link PublisherVerification#maxElementsFromPublisher()} to mark that the given {@link org.reactivestreams.Publisher},
+   * is not able to signal completion. For example it is strictly a time-bound or unbounded source of data.
+   *
+   * <b>Returning this value from {@link PublisherVerification#maxElementsFromPublisher()} will result in skipping all TCK tests which require onComplete signals!</b>
+   */
+  public long publisherUnableToSignalOnComplete() {
+    return Long.MAX_VALUE;
+  }
+
+  public void notVerified(String message) {
+    throw new SkipException(message);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/SubscriberBlackboxVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.tck.TestEnvironment.ManualPublisher;
+import org.reactivestreams.tck.TestEnvironment.ManualSubscriber;
+import org.reactivestreams.tck.flow.support.Optional;
+import org.reactivestreams.tck.flow.support.SubscriberBlackboxVerificationRules;
+import org.reactivestreams.tck.flow.support.TestException;
+import org.testng.SkipException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.reactivestreams.tck.SubscriberWhiteboxVerification.BlackboxSubscriberProxy;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Provides tests for verifying {@link org.reactivestreams.Subscriber} and {@link org.reactivestreams.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 {@code org.reactivestreams.tck.SubscriberWhiteboxVerification}
+ * instead.
+ *
+ * @see org.reactivestreams.Subscriber
+ * @see org.reactivestreams.Subscription
+ */
+public abstract class SubscriberBlackboxVerification<T> extends WithHelperPublisher<T>
+  implements SubscriberBlackboxVerificationRules {
+
+  protected final TestEnvironment env;
+
+  protected SubscriberBlackboxVerification(TestEnvironment env) {
+    this.env = env;
+  }
+
+  // USER API
+
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+   */
+  public abstract Subscriber<T> createSubscriber();
+
+  /**
+   * Override this method if the Subscriber implementation you are verifying
+   * needs an external signal before it signals demand to its Publisher.
+   *
+   * By default this method does nothing.
+   */
+  public void triggerRequest(final Subscriber<? super T> subscriber) {
+    // this method is intentionally left blank
+  }
+
+  // ENV SETUP
+
+  /**
+   * Executor service used by the default provided asynchronous Publisher.
+   * @see #createHelperPublisher(long)
+   */
+  private ExecutorService publisherExecutor;
+  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+
+  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+
+  @BeforeMethod
+  public void setUp() throws Exception {
+    env.clearAsyncErrors();
+  }
+
+  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+
+  @Override @Test
+  public void required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+      @Override
+      public void run(BlackboxTestStage stage) throws InterruptedException {
+        triggerRequest(stage.subProxy().sub());
+        final long requested = stage.expectRequest();// assuming subscriber wants to consume elements...
+        final long signalsToEmit = Math.min(requested, 512); // protecting against Subscriber which sends ridiculous large demand
+
+        // should cope with up to requested number of elements
+        for (int i = 0; i < signalsToEmit && sampleIsCancelled(stage, i, 10); i++)
+          stage.signalNext();
+
+        // we complete after `signalsToEmit` (which can be less than `requested`),
+        // which is legal under https://github.com/reactive-streams/reactive-streams-jvm#1.2
+        stage.sendCompletion();
+      }
+
+      /**
+       * In order to allow some "skid" and not check state on each iteration,
+       * only check {@code stage.isCancelled} every {@code checkInterval}'th iteration.
+       */
+      private boolean sampleIsCancelled(BlackboxTestStage stage, int i, int checkInterval) throws InterruptedException {
+        if (i % checkInterval == 0) return stage.isCancelled();
+        else return false;
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec202_blackbox_shouldAsynchronouslyDispatch() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+      @Override
+      public void run(BlackboxTestStage stage) throws Throwable {
+        final Subscription subs = new Subscription() {
+          @Override
+          public void request(long n) {
+            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+            if (onCompleteStackTraceElement.isDefined()) {
+              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+            }
+          }
+
+          @Override
+          public void cancel() {
+            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+            if (onCompleteStackElement.isDefined()) {
+              final StackTraceElement stackElem = onCompleteStackElement.get();
+              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+            }
+          }
+        };
+
+        final Subscriber<T> sub = createSubscriber();
+        sub.onSubscribe(subs);
+        sub.onComplete();
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+      @Override
+      public void run(BlackboxTestStage stage) throws Throwable {
+        final Subscription subs = new Subscription() {
+          @Override
+          public void request(long n) {
+            Throwable thr = new Throwable();
+            for (StackTraceElement stackElem : thr.getStackTrace()) {
+              if (stackElem.getMethodName().equals("onError")) {
+                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+              }
+            }
+          }
+
+          @Override
+          public void cancel() {
+            Throwable thr = new Throwable();
+            for (StackTraceElement stackElem : thr.getStackTrace()) {
+              if (stackElem.getMethodName().equals("onError")) {
+                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+              }
+            }
+          }
+        };
+
+        final Subscriber<T> sub = createSubscriber();
+        sub.onSubscribe(subs);
+        sub.onError(new TestException());
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Exception {
+    new BlackboxTestStage(env) {{
+      // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+      final TestEnvironment.Latch secondSubscriptionCancelled = new TestEnvironment.Latch(env);
+      sub().onSubscribe(
+          new Subscription() {
+            @Override
+            public void request(long elements) {
+              env.flop(String.format("Subscriber %s illegally called `subscription.request(%s)`!", sub(), elements));
+            }
+
+            @Override
+            public void cancel() {
+              secondSubscriptionCancelled.close();
+            }
+
+            @Override
+            public String toString() {
+              return "SecondSubscription(should get cancelled)";
+            }
+          });
+
+      secondSubscriptionCancelled.expectClose("Expected SecondSubscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called.");
+      env.verifyNoAsyncErrorsNoDelay();
+      sendCompletion(); // we're done, complete the subscriber under test
+    }};
+  }
+
+  @Override @Test
+  public void untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+    // the same thread part of the clause can be verified but that is not very useful, or is it?
+  }
+
+  @Override @Test
+  public void untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+    notVerified(); // cannot be meaningfully tested as black box, or can it?
+  }
+
+  @Override @Test
+  public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+      public void run(BlackboxTestStage stage) throws Throwable {
+        triggerRequest(stage.subProxy().sub());
+        final long notUsed = stage.expectRequest(); // received request signal
+        stage.sub().onComplete();
+        stage.subProxy().expectCompletion();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+      public void run(BlackboxTestStage stage) throws Throwable {
+        final Subscriber<? super T> sub = stage.sub();
+        sub.onComplete();
+        stage.subProxy().expectCompletion();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+      public void run(BlackboxTestStage stage) throws Throwable {
+        triggerRequest(stage.subProxy().sub());
+        final long notUsed = stage.expectRequest(); // received request signal
+        stage.sub().onError(new TestException()); // in response to that, we fail
+        stage.subProxy().expectError(Throwable.class);
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+  @Override @Test
+  public void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+    blackboxSubscriberTest(new BlackboxTestStageTestRun() {
+      @Override @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+      public void run(BlackboxTestStage stage) throws Throwable {
+
+        stage.sub().onError(new TestException());
+        stage.subProxy().expectError(Throwable.class);
+      }
+    });
+  }
+
+  @Override @Test
+  public void untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() throws Throwable {
+    notVerified(); // cannot be meaningfully tested as black box, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec213_blackbox_failingOnSignalInvocation() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+      @Override
+      public void run(BlackboxTestStage stage) throws Throwable {
+
+        {
+          final Subscriber<T> sub = createSubscriber();
+          boolean gotNPE = false;
+          try {
+            sub.onSubscribe(null);
+          } catch(final NullPointerException expected) {
+            gotNPE = true;
+          }
+          assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+        }
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+      @Override
+      public void run(BlackboxTestStage stage) throws Throwable {
+        final Subscription subscription = new Subscription() {
+          @Override public void request(final long elements) {}
+          @Override public void cancel() {}
+        };
+
+        {
+          final Subscriber<T> sub = createSubscriber();
+          boolean gotNPE = false;
+          sub.onSubscribe(subscription);
+          try {
+            sub.onNext(null);
+          } catch(final NullPointerException expected) {
+            gotNPE = true;
+          }
+          assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+        }
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  @Override @Test
+  public void required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    blackboxSubscriberWithoutSetupTest(new BlackboxTestStageTestRun() {
+      @Override
+      public void run(BlackboxTestStage stage) throws Throwable {
+        final Subscription subscription = new Subscription() {
+          @Override public void request(final long elements) {}
+          @Override public void cancel() {}
+        };
+
+        {
+          final Subscriber<T> sub = createSubscriber();
+          boolean gotNPE = false;
+          sub.onSubscribe(subscription);
+          try {
+            sub.onError(null);
+          } catch(final NullPointerException expected) {
+            gotNPE = true;
+          }
+          assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+        }
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+
+  @Override @Test
+  public void untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+    notVerified(); // cannot be meaningfully tested as black box, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  @Override @Test
+  public void untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+
+  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+
+  abstract class BlackboxTestStageTestRun {
+    public abstract void run(BlackboxTestStage stage) throws Throwable;
+  }
+
+  public void blackboxSubscriberTest(BlackboxTestStageTestRun body) throws Throwable {
+    BlackboxTestStage stage = new BlackboxTestStage(env, true);
+    body.run(stage);
+  }
+
+  public void blackboxSubscriberWithoutSetupTest(BlackboxTestStageTestRun body) throws Throwable {
+    BlackboxTestStage stage = new BlackboxTestStage(env, false);
+    body.run(stage);
+  }
+
+  public class BlackboxTestStage extends ManualPublisher<T> {
+    public Publisher<T> pub;
+    public ManualSubscriber<T> tees; // gives us access to an infinite stream of T values
+
+    public T lastT = null;
+    private Optional<BlackboxSubscriberProxy<T>> subProxy = Optional.empty();
+
+    public BlackboxTestStage(TestEnvironment env) throws InterruptedException {
+      this(env, true);
+    }
+
+    public BlackboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+      super(env);
+      if (runDefaultInit) {
+        pub = this.createHelperPublisher(Long.MAX_VALUE);
+        tees = env.newManualSubscriber(pub);
+        Subscriber<T> sub = createSubscriber();
+        subProxy = Optional.of(createBlackboxSubscriberProxy(env, sub));
+        subscribe(subProxy.get());
+      }
+    }
+
+    public Subscriber<? super T> sub() {
+      return subscriber.value();
+    }
+
+    /**
+     * Proxy for the {@link #sub()} {@code Subscriber}, providing certain assertions on methods being called on the Subscriber.
+     */
+    public BlackboxSubscriberProxy<T> subProxy() {
+      return subProxy.get();
+    }
+
+    public Publisher<T> createHelperPublisher(long elements) {
+      return SubscriberBlackboxVerification.this.createHelperPublisher(elements);
+    }
+
+    public BlackboxSubscriberProxy<T> createBlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> sub) {
+      return new BlackboxSubscriberProxy<T>(env, sub);
+    }
+
+    public T signalNext() throws InterruptedException {
+      T element = nextT();
+      sendNext(element);
+      return element;
+    }
+
+    public T nextT() throws InterruptedException {
+      lastT = tees.requestNextElement();
+      return lastT;
+    }
+
+  }
+
+  public void notVerified() {
+    throw new SkipException("Not verified using this TCK.");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/SubscriberWhiteboxVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.tck.TestEnvironment.*;
+import org.reactivestreams.tck.flow.support.Optional;
+import org.reactivestreams.tck.flow.support.SubscriberWhiteboxVerificationRules;
+import org.reactivestreams.tck.flow.support.TestException;
+import org.testng.SkipException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Provides whitebox style tests for verifying {@link org.reactivestreams.Subscriber}
+ * and {@link org.reactivestreams.Subscription} specification rules.
+ *
+ * @see org.reactivestreams.Subscriber
+ * @see org.reactivestreams.Subscription
+ */
+public abstract class SubscriberWhiteboxVerification<T> extends WithHelperPublisher<T>
+  implements SubscriberWhiteboxVerificationRules {
+
+  private final TestEnvironment env;
+
+  protected SubscriberWhiteboxVerification(TestEnvironment env) {
+    this.env = env;
+  }
+
+  // USER API
+
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+   *
+   * In order to be meaningfully testable your Subscriber must inform the given
+   * `WhiteboxSubscriberProbe` of the respective events having been received.
+   */
+  public abstract Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe);
+
+  // ENV SETUP
+
+  /**
+   * Executor service used by the default provided asynchronous Publisher.
+   * @see #createHelperPublisher(long)
+   */
+  private ExecutorService publisherExecutor;
+  @BeforeClass public void startPublisherExecutorService() { publisherExecutor = Executors.newFixedThreadPool(4); }
+  @AfterClass public void shutdownPublisherExecutorService() { if (publisherExecutor != null) publisherExecutor.shutdown(); }
+  @Override public ExecutorService publisherExecutorService() { return publisherExecutor; }
+
+  ////////////////////// TEST ENV CLEANUP /////////////////////////////////////
+
+  @BeforeMethod
+  public void setUp() throws Exception {
+    env.clearAsyncErrors();
+  }
+
+  ////////////////////// TEST SETUP VERIFICATION //////////////////////////////
+
+  @Test
+  public void required_exerciseWhiteboxHappyPath() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.puppet().triggerRequest(1);
+        stage.puppet().triggerRequest(1);
+
+        long receivedRequests = stage.expectRequest();
+
+        stage.signalNext();
+        stage.probe.expectNext(stage.lastT);
+
+        stage.puppet().triggerRequest(1);
+        if (receivedRequests == 1) {
+          stage.expectRequest();
+        }
+
+        stage.signalNext();
+        stage.probe.expectNext(stage.lastT);
+
+        stage.puppet().signalCancel();
+        stage.expectCancelling();
+
+        stage.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  ////////////////////// SPEC RULE VERIFICATION ///////////////////////////////
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.1
+  @Override @Test
+  public void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.puppet().triggerRequest(1);
+        stage.expectRequest();
+
+        stage.signalNext();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.2
+  @Override @Test
+  public void untested_spec202_shouldAsynchronouslyDispatch() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+  @Override @Test
+  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable {
+    subscriberTestWithoutSetup(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws Throwable {
+        final Subscription subs = new Subscription() {
+          @Override
+          public void request(long n) {
+            final Optional<StackTraceElement> onCompleteStackTraceElement = env.findCallerMethodInStackTrace("onComplete");
+            if (onCompleteStackTraceElement.isDefined()) {
+              final StackTraceElement stackElem = onCompleteStackTraceElement.get();
+              env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+            }
+          }
+
+          @Override
+          public void cancel() {
+            final Optional<StackTraceElement> onCompleteStackElement = env.findCallerMethodInStackTrace("onComplete");
+            if (onCompleteStackElement.isDefined()) {
+              final StackTraceElement stackElem = onCompleteStackElement.get();
+              env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onComplete (Rule 2.3)! (Caller: %s::%s line %d)",
+                                     stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+            }
+          }
+        };
+
+        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+        final Subscriber<T> sub = createSubscriber(stage.probe);
+
+        sub.onSubscribe(subs);
+        sub.onComplete();
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.3
+  @Override @Test
+  public void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable {
+    subscriberTestWithoutSetup(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws Throwable {
+        final Subscription subs = new Subscription() {
+          @Override
+          public void request(long n) {
+            Throwable thr = new Throwable();
+            for (StackTraceElement stackElem : thr.getStackTrace()) {
+              if (stackElem.getMethodName().equals("onError")) {
+                env.flop(String.format("Subscription::request MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+              }
+            }
+          }
+
+          @Override
+          public void cancel() {
+            Throwable thr = new Throwable();
+            for (StackTraceElement stackElem : thr.getStackTrace()) {
+              if (stackElem.getMethodName().equals("onError")) {
+                env.flop(String.format("Subscription::cancel MUST NOT be called from Subscriber::onError (Rule 2.3)! (Caller: %s::%s line %d)",
+                                       stackElem.getClassName(), stackElem.getMethodName(), stackElem.getLineNumber()));
+              }
+            }
+          }
+        };
+
+        stage.probe = stage.createWhiteboxSubscriberProbe(env);
+        final Subscriber<T> sub = createSubscriber(stage.probe);
+
+        sub.onSubscribe(subs);
+        sub.onError(new TestException());
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.4
+  @Override @Test
+  public void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.5
+  @Override @Test
+  public void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws Throwable {
+        // try to subscribe another time, if the subscriber calls `probe.registerOnSubscribe` the test will fail
+        final Latch secondSubscriptionCancelled = new Latch(env);
+        final Subscriber<? super T> sub = stage.sub();
+        final Subscription subscription = new Subscription() {
+          @Override
+          public void request(long elements) {
+            // ignore...
+          }
+
+          @Override
+          public void cancel() {
+            secondSubscriptionCancelled.close();
+          }
+
+          @Override
+          public String toString() {
+            return "SecondSubscription(should get cancelled)";
+          }
+        };
+        sub.onSubscribe(subscription);
+
+        secondSubscriptionCancelled.expectClose("Expected 2nd Subscription given to subscriber to be cancelled, but `Subscription.cancel()` was not called");
+        env.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.6
+  @Override @Test
+  public void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.7
+  @Override @Test
+  public void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+    // the same thread part of the clause can be verified but that is not very useful, or is it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.8
+  @Override @Test
+  public void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.puppet().triggerRequest(1);
+        stage.puppet().signalCancel();
+        stage.expectRequest();
+        stage.signalNext();
+
+        stage.puppet().triggerRequest(1);
+        stage.puppet().triggerRequest(1);
+
+        stage.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+  @Override @Test
+  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.puppet().triggerRequest(1);
+        stage.sendCompletion();
+        stage.probe.expectCompletion();
+
+        stage.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.9
+  @Override @Test
+  public void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.sendCompletion();
+        stage.probe.expectCompletion();
+
+        stage.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+  @Override @Test
+  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.puppet().triggerRequest(1);
+        stage.puppet().triggerRequest(1);
+
+        Exception ex = new TestException();
+        stage.sendError(ex);
+        stage.probe.expectError(ex);
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.10
+  @Override @Test
+  public void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        Exception ex = new TestException();
+        stage.sendError(ex);
+        stage.probe.expectError(ex);
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.11
+  @Override @Test
+  public void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.12
+  @Override @Test
+  public void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+  @Override @Test
+  public void untested_spec213_failingOnSignalInvocation() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+  @Override @Test
+  public void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws Throwable {
+
+        final Subscriber<? super T> sub = stage.sub();
+        boolean gotNPE = false;
+        try {
+          sub.onSubscribe(null);
+        } catch (final NullPointerException expected) {
+          gotNPE = true;
+        }
+
+        assertTrue(gotNPE, "onSubscribe(null) did not throw NullPointerException");
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+  @Override @Test
+  public void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws Throwable {
+
+        final Subscriber<? super T> sub = stage.sub();
+        boolean gotNPE = false;
+        try {
+          sub.onNext(null);
+        } catch (final NullPointerException expected) {
+          gotNPE = true;
+        }
+
+        assertTrue(gotNPE, "onNext(null) did not throw NullPointerException");
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#2.13
+  @Override @Test
+  public void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws Throwable {
+
+          final Subscriber<? super T> sub = stage.sub();
+          boolean gotNPE = false;
+          try {
+            sub.onError(null);
+          } catch (final NullPointerException expected) {
+            gotNPE = true;
+          } finally {
+            assertTrue(gotNPE, "onError(null) did not throw NullPointerException");
+          }
+
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    });
+  }
+
+
+  ////////////////////// SUBSCRIPTION SPEC RULE VERIFICATION //////////////////
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.1
+  @Override @Test
+  public void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.8
+  @Override @Test
+  public void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable {
+    subscriberTest(new TestStageTestRun() {
+      @Override
+      public void run(WhiteboxTestStage stage) throws InterruptedException {
+        stage.puppet().triggerRequest(2);
+        long requestedElements = stage.expectRequest();
+        stage.probe.expectNext(stage.signalNext());
+        // Some subscribers may only request one element at a time.
+        if (requestedElements < 2) {
+          stage.expectRequest();
+        }
+        stage.probe.expectNext(stage.signalNext());
+
+        stage.probe.expectNone();
+        stage.puppet().triggerRequest(3);
+
+        stage.verifyNoAsyncErrors();
+      }
+    });
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.10
+  @Override @Test
+  public void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.11
+  @Override @Test
+  public void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.14
+  @Override @Test
+  public void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.15
+  @Override @Test
+  public void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  // Verifies rule: https://github.com/reactive-streams/reactive-streams-jvm#3.16
+  @Override @Test
+  public void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception {
+    notVerified(); // cannot be meaningfully tested, or can it?
+  }
+
+  /////////////////////// ADDITIONAL "COROLLARY" TESTS ////////////////////////
+
+  /////////////////////// TEST INFRASTRUCTURE /////////////////////////////////
+
+  abstract class TestStageTestRun {
+    public abstract void run(WhiteboxTestStage stage) throws Throwable;
+  }
+
+  /**
+   * Prepares subscriber and publisher pair (by subscribing the first to the latter),
+   * and then hands over the tests {@link WhiteboxTestStage} over to the test.
+   *
+   * The test stage is, like in a puppet show, used to orchestrate what each participant should do.
+   * Since this is a whitebox test, this allows the stage to completely control when and how to signal / expect signals.
+   */
+  public void subscriberTest(TestStageTestRun body) throws Throwable {
+    WhiteboxTestStage stage = new WhiteboxTestStage(env, true);
+    body.run(stage);
+  }
+
+  /**
+   * Provides a {@link WhiteboxTestStage} without performing any additional setup,
+   * like the {@link #subscriberTest(SubscriberWhiteboxVerification.TestStageTestRun)} would.
+   *
+   * Use this method to write tests in which you need full control over when and how the initial {@code subscribe} is signalled.
+   */
+  public void subscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+    WhiteboxTestStage stage = new WhiteboxTestStage(env, false);
+    body.run(stage);
+  }
+
+  /**
+   * Test for feature that MAY be implemented. This test will be marked as SKIPPED if it fails.
+   */
+  public void optionalSubscriberTestWithoutSetup(TestStageTestRun body) throws Throwable {
+    try {
+      subscriberTestWithoutSetup(body);
+    } catch (Exception ex) {
+      notVerified("Skipped because tested publisher does NOT implement this OPTIONAL requirement.");
+    }
+  }
+
+  public class WhiteboxTestStage extends ManualPublisher<T> {
+    public Publisher<T> pub;
+    public ManualSubscriber<T> tees; // gives us access to a stream T values
+    public WhiteboxSubscriberProbe<T> probe;
+
+    public T lastT = null;
+
+    public WhiteboxTestStage(TestEnvironment env) throws InterruptedException {
+      this(env, true);
+    }
+
+    public WhiteboxTestStage(TestEnvironment env, boolean runDefaultInit) throws InterruptedException {
+      super(env);
+      if (runDefaultInit) {
+        pub = this.createHelperPublisher(Long.MAX_VALUE);
+        tees = env.newManualSubscriber(pub);
+        probe = new WhiteboxSubscriberProbe<T>(env, subscriber);
+        subscribe(createSubscriber(probe));
+        probe.puppet.expectCompletion(env.defaultTimeoutMillis(), String.format("Subscriber %s did not `registerOnSubscribe`", sub()));
+        env.verifyNoAsyncErrorsNoDelay();
+      }
+    }
+
+    public Subscriber<? super T> sub() {
+      return subscriber.value();
+    }
+
+    public SubscriberPuppet puppet() {
+      return probe.puppet();
+    }
+
+    public WhiteboxSubscriberProbe<T> probe() {
+      return probe;
+    }
+
+    public Publisher<T> createHelperPublisher(long elements) {
+      return SubscriberWhiteboxVerification.this.createHelperPublisher(elements);
+    }
+
+    public WhiteboxSubscriberProbe<T> createWhiteboxSubscriberProbe(TestEnvironment env) {
+      return new WhiteboxSubscriberProbe<T>(env, subscriber);
+    }
+
+    public T signalNext() throws InterruptedException {
+      return signalNext(nextT());
+    }
+
+    private T signalNext(T element) throws InterruptedException {
+      sendNext(element);
+      return element;
+    }
+
+    public T nextT() throws InterruptedException {
+      lastT = tees.requestNextElement();
+      return lastT;
+    }
+
+    public void verifyNoAsyncErrors() {
+      env.verifyNoAsyncErrors();
+    }
+  }
+
+  /**
+   * This class is intented to be used as {@code Subscriber} decorator and should be used in {@code pub.subscriber(...)} calls,
+   * in order to allow intercepting calls on the underlying {@code Subscriber}.
+   * This delegation allows the proxy to implement {@link BlackboxProbe} assertions.
+   */
+  public static class BlackboxSubscriberProxy<T> extends BlackboxProbe<T> implements Subscriber<T> {
+
+    public BlackboxSubscriberProxy(TestEnvironment env, Subscriber<T> subscriber) {
+      super(env, Promise.<Subscriber<? super T>>completed(env, subscriber));
+    }
+
+    @Override
+    public void onSubscribe(Subscription s) {
+      sub().onSubscribe(s);
+    }
+
+    @Override
+    public void onNext(T t) {
+      registerOnNext(t);
+      sub().onNext(t);
+    }
+
+    @Override
+    public void onError(Throwable cause) {
+      registerOnError(cause);
+      sub().onError(cause);
+    }
+
+    @Override
+    public void onComplete() {
+      registerOnComplete();
+      sub().onComplete();
+    }
+  }
+
+  public static class BlackboxProbe<T> implements SubscriberProbe<T> {
+    protected final TestEnvironment env;
+    protected final Promise<Subscriber<? super T>> subscriber;
+
+    protected final Receptacle<T> elements;
+    protected final Promise<Throwable> error;
+
+    public BlackboxProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+      this.env = env;
+      this.subscriber = subscriber;
+      elements = new Receptacle<T>(env);
+      error = new Promise<Throwable>(env);
+    }
+
+    @Override
+    public void registerOnNext(T element) {
+      elements.add(element);
+    }
+
+    @Override
+    public void registerOnComplete() {
+      try {
+        elements.complete();
+      } catch (IllegalStateException ex) {
+        // "Queue full", onComplete was already called
+        env.flop("subscriber::onComplete was called a second time, which is illegal according to Rule 1.7");
+      }
+    }
+
+    @Override
+    public void registerOnError(Throwable cause) {
+      try {
+        error.complete(cause);
+      } catch (IllegalStateException ex) {
+        // "Queue full", onError was already called
+        env.flop("subscriber::onError was called a second time, which is illegal according to Rule 1.7");
+      }
+    }
+
+    public T expectNext() throws InterruptedException {
+      return elements.next(env.defaultTimeoutMillis(), String.format("Subscriber %s did not call `registerOnNext(_)`", sub()));
+    }
+
+    public void expectNext(T expected) throws InterruptedException {
+      expectNext(expected, env.defaultTimeoutMillis());
+    }
+
+    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+      T received = elements.next(timeoutMillis, String.format("Subscriber %s did not call `registerOnNext(%s)`", sub(), expected));
+      if (!received.equals(expected)) {
+        env.flop(String.format("Subscriber %s called `registerOnNext(%s)` rather than `registerOnNext(%s)`", sub(), received, expected));
+      }
+    }
+
+    public Subscriber<? super T> sub() {
+      return subscriber.value();
+    }
+
+    public void expectCompletion() throws InterruptedException {
+      expectCompletion(env.defaultTimeoutMillis());
+    }
+
+    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+      expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnComplete()`", sub()));
+    }
+
+    public void expectCompletion(long timeoutMillis, String msg) throws InterruptedException {
+      elements.expectCompletion(timeoutMillis, msg);
+    }
+
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws InterruptedException {
+      final E err = expectError(expected);
+      String message = err.getMessage();
+      assertTrue(message.contains(requiredMessagePart),
+        String.format("Got expected exception %s but missing message [%s], was: %s", err.getClass(), requiredMessagePart, expected));
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected) throws InterruptedException {
+      return expectError(expected, env.defaultTimeoutMillis());
+    }
+
+    @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"})
+    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws InterruptedException {
+      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+      if (error.value() == null) {
+        return env.flopAndFail(String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+      } else if (expected.isInstance(error.value())) {
+        return (E) error.value();
+      } else {
+        return env.flopAndFail(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+      }
+    }
+
+    public void expectError(Throwable expected) throws InterruptedException {
+      expectError(expected, env.defaultTimeoutMillis());
+    }
+
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    public void expectError(Throwable expected, long timeoutMillis) throws InterruptedException {
+      error.expectCompletion(timeoutMillis, String.format("Subscriber %s did not call `registerOnError(%s)`", sub(), expected));
+      if (error.value() != expected) {
+        env.flop(String.format("Subscriber %s called `registerOnError(%s)` rather than `registerOnError(%s)`", sub(), error.value(), expected));
+      }
+    }
+
+    public void expectNone() throws InterruptedException {
+      expectNone(env.defaultNoSignalsTimeoutMillis());
+    }
+
+    public void expectNone(long withinMillis) throws InterruptedException {
+      elements.expectNone(withinMillis, "Expected nothing");
+    }
+
+  }
+
+  public static class WhiteboxSubscriberProbe<T> extends BlackboxProbe<T> implements SubscriberPuppeteer {
+    protected Promise<SubscriberPuppet> puppet;
+
+    public WhiteboxSubscriberProbe(TestEnvironment env, Promise<Subscriber<? super T>> subscriber) {
+      super(env, subscriber);
+      puppet = new Promise<SubscriberPuppet>(env);
+    }
+
+    private SubscriberPuppet puppet() {
+      return puppet.value();
+    }
+
+    @Override
+    public void registerOnSubscribe(SubscriberPuppet p) {
+      if (!puppet.isCompleted()) {
+        puppet.complete(p);
+      }
+    }
+
+  }
+
+  public interface SubscriberPuppeteer {
+
+    /**
+     * Must be called by the test subscriber when it has successfully registered a subscription
+     * inside the `onSubscribe` method.
+     */
+    void registerOnSubscribe(SubscriberPuppet puppet);
+  }
+
+  public interface SubscriberProbe<T> {
+
+    /**
+     * Must be called by the test subscriber when it has received an`onNext` event.
+     */
+    void registerOnNext(T element);
+
+    /**
+     * Must be called by the test subscriber when it has received an `onComplete` event.
+     */
+    void registerOnComplete();
+
+    /**
+     * Must be called by the test subscriber when it has received an `onError` event.
+     */
+    void registerOnError(Throwable cause);
+
+  }
+
+  /**
+   * Implement this puppet in your Whitebox style tests.
+   * The test suite will invoke the specific trigger/signal methods requesting you to execute the specific action.
+   * Since this is a whitebox style test, you're allowed and expected to use knowladge about your implementation to
+   * make implement these calls.
+   */
+  public interface SubscriberPuppet {
+
+    /**
+     * Ensure that at least {@code elements} are eventually requested by your {@link Subscriber}, if it hasn't already
+     * requested that many elements.
+     * <p>
+     * This does not necessarily have to correlate 1:1 with a {@code Subscription.request(elements)} call, but the sum
+     * of the elements requested by your {@code Subscriber} must eventually be at least the the sum of the elements
+     * triggered to be requested by all the invocations of this method.
+     * <p>
+     * Additionally, subscribers are permitted to delay requesting elements until previous requests for elements have
+     * been fulfilled. For example, a subscriber that only requests one element at a time may fulfill the request made
+     * by this method by requesting one element {@code elements} times, waiting for each element to arrive before the
+     * next request is made.
+     * <p>
+     * Before sending any element to the subscriber, the TCK must wait for the subscriber to request that element, and
+     * must be prepared for the subscriber to only request one element at a time, it is not enough for the TCK to
+     * simply invoke this method before sending elements.
+     */
+    void triggerRequest(long elements);
+
+    /**
+     * Trigger {@code cancel()} on your {@link Subscriber}
+     */
+    void signalCancel();
+  }
+
+  public void notVerified() {
+    throw new SkipException("Not verified using this TCK.");
+  }
+
+  public void notVerified(String msg) {
+    throw new SkipException(msg);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/TestEnvironment.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,1168 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.tck.flow.support.Optional;
+import org.reactivestreams.tck.flow.support.SubscriberBufferOverflowException;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+public class TestEnvironment {
+  public static final int TEST_BUFFER_SIZE = 16;
+
+  private static final String DEFAULT_TIMEOUT_MILLIS_ENV = "DEFAULT_TIMEOUT_MILLIS";
+  private static final long DEFAULT_TIMEOUT_MILLIS = 100;
+
+  private static final String DEFAULT_NO_SIGNALS_TIMEOUT_MILLIS_ENV = "DEFAULT_NO_SIGNALS_TIMEOUT_MILLIS";
+  private static final String DEFAULT_POLL_TIMEOUT_MILLIS_ENV = "DEFAULT_POLL_TIMEOUT_MILLIS_ENV";
+
+  private final long defaultTimeoutMillis;
+  private final long defaultPollTimeoutMillis;
+  private final long defaultNoSignalsTimeoutMillis;
+  private final boolean printlnDebug;
+
+  private CopyOnWriteArrayList<Throwable> asyncErrors = new CopyOnWriteArrayList<Throwable>();
+
+  /**
+   * 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.
+   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+   * @param defaultNoSignalsTimeoutMillis default timeout to be used when no further signals are expected anymore
+   * @param defaultPollTimeoutMillis default amount of time to poll for events if {@code defaultTimeoutMillis} isn't
+    *                                preempted by an asynchronous event.
+   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+   */
+  public TestEnvironment(long defaultTimeoutMillis, long defaultNoSignalsTimeoutMillis, long defaultPollTimeoutMillis,
+                         boolean printlnDebug) {
+    this.defaultTimeoutMillis = defaultTimeoutMillis;
+    this.defaultPollTimeoutMillis = defaultPollTimeoutMillis;
+    this.defaultNoSignalsTimeoutMillis = defaultNoSignalsTimeoutMillis;
+    this.printlnDebug = 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.
+   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+   * @param defaultNoSignalsTimeoutMillis default timeout to be used when no further signals are expected anymore
+   * @param printlnDebug         if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+   */
+  public TestEnvironment(long defaultTimeoutMillis, long defaultNoSignalsTimeoutMillis, boolean printlnDebug) {
+    this(defaultTimeoutMillis, defaultNoSignalsTimeoutMillis, defaultTimeoutMillis, 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.
+   *
+   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+   * @param defaultNoSignalsTimeoutMillis default timeout to be used when no further signals are expected anymore
+   * @param defaultPollTimeoutMillis default amount of time to poll for events if {@code defaultTimeoutMillis} isn't
+   *                                 preempted by an asynchronous event.
+   */
+  public TestEnvironment(long defaultTimeoutMillis, long defaultNoSignalsTimeoutMillis, long defaultPollTimeoutMillis) {
+      this(defaultTimeoutMillis, defaultNoSignalsTimeoutMillis, defaultPollTimeoutMillis, false);
+  }
+
+  /**
+   * 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.
+   *
+   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+   * @param defaultNoSignalsTimeoutMillis default timeout to be used when no further signals are expected anymore
+   */
+  public TestEnvironment(long defaultTimeoutMillis, long defaultNoSignalsTimeoutMillis) {
+    this(defaultTimeoutMillis, defaultTimeoutMillis, defaultNoSignalsTimeoutMillis);
+  }
+
+  /**
+   * 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.
+   *
+   * @param defaultTimeoutMillis default timeout to be used in all expect* methods
+   */
+  public TestEnvironment(long defaultTimeoutMillis) {
+    this(defaultTimeoutMillis, defaultTimeoutMillis, 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.
+   *
+   * The default timeout for all expect* methods will be obtained by either the env variable {@code DEFAULT_TIMEOUT_MILLIS}
+   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+   *
+   * @param printlnDebug if true, signals such as OnNext / Request / OnComplete etc will be printed to standard output,
+   *                     often helpful to pinpoint simple race conditions etc.
+   */
+  public TestEnvironment(boolean printlnDebug) {
+    this(envDefaultTimeoutMillis(), envDefaultNoSignalsTimeoutMillis(), envDefaultPollTimeoutMillis(), 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 {@code DEFAULT_TIMEOUT_MILLIS}
+   * or the default value ({@link TestEnvironment#DEFAULT_TIMEOUT_MILLIS}) will be used.
+   */
+  public TestEnvironment() {
+    this(envDefaultTimeoutMillis(), envDefaultNoSignalsTimeoutMillis());
+  }
+
+  /** This timeout is used when waiting for a signal to arrive. */
+  public long defaultTimeoutMillis() {
+    return defaultTimeoutMillis;
+  }
+
+  /**
+   * This timeout is used when asserting that no further signals are emitted.
+   * Note that this timeout default
+   */
+  public long defaultNoSignalsTimeoutMillis() {
+    return defaultNoSignalsTimeoutMillis;
+  }
+
+  /**
+   * The default amount of time to poll for events if {@code defaultTimeoutMillis} isn't preempted by an asynchronous
+   * event.
+   */
+  public long defaultPollTimeoutMillis() {
+    return defaultPollTimeoutMillis;
+  }
+
+  /**
+   * Tries to parse the env variable {@code 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
+   */
+  public static long envDefaultTimeoutMillis() {
+    final String envMillis = System.getenv(DEFAULT_TIMEOUT_MILLIS_ENV);
+    if (envMillis == null) return DEFAULT_TIMEOUT_MILLIS;
+    else try {
+      return Long.parseLong(envMillis);
+    } catch (NumberFormatException ex) {
+      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_TIMEOUT_MILLIS_ENV, envMillis), ex);
+    }
+  }
+
+  /**
+   * Tries to parse the env variable {@code DEFAULT_NO_SIGNALS_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
+   */
+  public static long envDefaultNoSignalsTimeoutMillis() {
+    final String envMillis = System.getenv(DEFAULT_NO_SIGNALS_TIMEOUT_MILLIS_ENV);
+    if (envMillis == null) return envDefaultTimeoutMillis();
+    else try {
+      return Long.parseLong(envMillis);
+    } catch (NumberFormatException ex) {
+      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_NO_SIGNALS_TIMEOUT_MILLIS_ENV, envMillis), ex);
+    }
+  }
+
+  /**
+   * Tries to parse the env variable {@code DEFAULT_POLL_TIMEOUT_MILLIS_ENV} as long and returns the value if present OR its default value.
+   *
+   * @throws java.lang.IllegalArgumentException when unable to parse the env variable
+   */
+  public static long envDefaultPollTimeoutMillis() {
+    final String envMillis = System.getenv(DEFAULT_POLL_TIMEOUT_MILLIS_ENV);
+    if (envMillis == null) return envDefaultTimeoutMillis();
+    else try {
+      return Long.parseLong(envMillis);
+    } catch (NumberFormatException ex) {
+      throw new IllegalArgumentException(String.format("Unable to parse %s env value [%s] as long!", DEFAULT_POLL_TIMEOUT_MILLIS_ENV, envMillis), ex);
+    }
+  }
+
+  /**
+   * 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 {@code 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 {@code expectError} methods or collect the error directly
+   * from the environment using {@code env.dropAsyncError()}.
+   *
+   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+   */
+  public void flop(String msg) {
+    try {
+      fail(msg);
+    } catch (Throwable t) {
+      asyncErrors.add(t);
+    }
+  }
+
+  /**
+   * 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 {@code 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 {@code expectError} methods or collect the error directly
+   * from the environment using {@code env.dropAsyncError()}.
+   *
+   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+   */
+  public void flop(Throwable thr, String msg) {
+    try {
+      fail(msg, thr);
+    } catch (Throwable t) {
+      asyncErrors.add(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 {@code 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 {@code expectError} methods or collect the error directly
+   * from the environment using {@code env.dropAsyncError()}.
+   *
+   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+   */
+  public void flop(Throwable thr) {
+    try {
+      fail(thr.getMessage(), thr);
+    } catch (Throwable t) {
+      asyncErrors.add(thr);
+    }
+  }
+
+  /**
+   * 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 {@link org.reactivestreams.tck.TestEnvironment#flop} which only records the error.
+   *
+   * Use {@code 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 {@code expectError} methods or collect the error directly
+   * from the environment using {@code env.dropAsyncError()}.
+   *
+   * To clear asyncErrors you can call {@link org.reactivestreams.tck.TestEnvironment#clearAsyncErrors()}
+   */
+  public <T> T flopAndFail(String msg) {
+    try {
+      fail(msg);
+    } catch (Throwable t) {
+      asyncErrors.add(t);
+      fail(msg, t);
+    }
+    return null; // unreachable, the previous block will always exit by throwing
+  }
+
+
+
+  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub) throws InterruptedException {
+    subscribe(pub, sub, defaultTimeoutMillis);
+  }
+
+  public <T> void subscribe(Publisher<T> pub, TestSubscriber<T> sub, long timeoutMillis) throws InterruptedException {
+    pub.subscribe(sub);
+    sub.subscription.expectCompletion(timeoutMillis, String.format("Could not subscribe %s to Publisher %s", sub, pub));
+    verifyNoAsyncErrorsNoDelay();
+  }
+
+  public <T> ManualSubscriber<T> newBlackholeSubscriber(Publisher<T> pub) throws InterruptedException {
+    ManualSubscriberWithSubscriptionSupport<T> sub = new BlackholeSubscriberWithSubscriptionSupport<T>(this);
+    subscribe(pub, sub, defaultTimeoutMillis());
+    return sub;
+  }
+
+  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub) throws InterruptedException {
+    return newManualSubscriber(pub, defaultTimeoutMillis());
+  }
+
+  public <T> ManualSubscriber<T> newManualSubscriber(Publisher<T> pub, long timeoutMillis) throws InterruptedException {
+    ManualSubscriberWithSubscriptionSupport<T> sub = new ManualSubscriberWithSubscriptionSupport<T>(this);
+    subscribe(pub, sub, timeoutMillis);
+    return sub;
+  }
+
+  public void clearAsyncErrors() {
+    asyncErrors.clear();
+  }
+
+  public Throwable dropAsyncError() {
+    try {
+      return asyncErrors.remove(0);
+    } catch (IndexOutOfBoundsException ex) {
+      return null;
+    }
+  }
+
+  /**
+   * Waits for {@link TestEnvironment#defaultNoSignalsTimeoutMillis()} and then verifies that no asynchronous errors
+   * were signalled pior to, or during that time (by calling {@code flop()}).
+   */
+  public void verifyNoAsyncErrors() {
+    verifyNoAsyncErrors(defaultNoSignalsTimeoutMillis());
+  }
+
+  /**
+   * This version of {@code verifyNoAsyncErrors} should be used when errors still could be signalled
+   * asynchronously during {@link TestEnvironment#defaultTimeoutMillis()} time.
+   * <p></p>
+   * It will immediatly check if any async errors were signaled (using {@link TestEnvironment#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.
+   */
+  public void verifyNoAsyncErrors(long delay) {
+    try {
+      verifyNoAsyncErrorsNoDelay();
+
+      Thread.sleep(delay);
+      verifyNoAsyncErrorsNoDelay();
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Verifies that no asynchronous errors were signalled pior to calling this method (by calling {@code flop()}).
+   * This version of verifyNoAsyncError <b>does not wait before checking for asynchronous errors</b>, and is to be used
+   * for example in tight loops etc.
+   */
+  public void verifyNoAsyncErrorsNoDelay() {
+    for (Throwable e : asyncErrors) {
+      if (e instanceof AssertionError) {
+        throw (AssertionError) e;
+      } else {
+        fail(String.format("Async error during test execution: %s", e.getMessage()), e);
+      }
+    }
+  }
+
+  /** If {@code TestEnvironment#printlnDebug} is true, print debug message to std out. */
+  public void debug(String msg) {
+    if (debugEnabled()) {
+      System.out.printf("[TCK-DEBUG] %s%n", msg);
+    }
+  }
+
+  public final boolean debugEnabled() {
+    return printlnDebug;
+  }
+
+  /**
+   * Looks for given {@code method} method in stack trace.
+   * Can be used to answer questions like "was this method called from onComplete?".
+   *
+   * @return the caller's StackTraceElement at which he the looked for method was found in the call stack, EMPTY otherwise
+   */
+  public Optional<StackTraceElement> findCallerMethodInStackTrace(String method) {
+    final Throwable thr = new Throwable(); // gets the stacktrace
+
+    for (StackTraceElement stackElement : thr.getStackTrace()) {
+      if (stackElement.getMethodName().equals(method)) {
+        return Optional.of(stackElement);
+      }
+    }
+    return Optional.empty();
+  }
+
+  // ---- classes ----
+
+  /**
+   * {@link Subscriber} implementation which can be steered by test code and asserted on.
+   */
+  public static class ManualSubscriber<T> extends TestSubscriber<T> {
+    Receptacle<T> received;
+
+    public ManualSubscriber(TestEnvironment env) {
+      super(env);
+      received = new Receptacle<T>(this.env);
+    }
+
+    @Override
+    public void onNext(T element) {
+      try {
+        received.add(element);
+      } catch (IllegalStateException ex) {
+          // error message refinement
+          throw new SubscriberBufferOverflowException(
+            String.format("Received more than bufferSize (%d) onNext signals. " +
+                            "The Publisher probably emited more signals than expected!",
+                          received.QUEUE_SIZE), ex);
+      }
+    }
+
+    @Override
+    public void onComplete() {
+      received.complete();
+    }
+
+    public void request(long elements) {
+      subscription.value().request(elements);
+    }
+
+    public T requestNextElement() throws InterruptedException {
+      return requestNextElement(env.defaultTimeoutMillis());
+    }
+
+    public T requestNextElement(long timeoutMillis) throws InterruptedException {
+      return requestNextElement(timeoutMillis, "Did not receive expected element");
+    }
+
+    public T requestNextElement(String errorMsg) throws InterruptedException {
+      return requestNextElement(env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public T requestNextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+      request(1);
+      return nextElement(timeoutMillis, errorMsg);
+    }
+
+    public Optional<T> requestNextElementOrEndOfStream() throws InterruptedException {
+      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+    }
+
+    public Optional<T> requestNextElementOrEndOfStream(String errorMsg) throws InterruptedException {
+      return requestNextElementOrEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+      return requestNextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+    }
+
+    public Optional<T> requestNextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+      request(1);
+      return nextElementOrEndOfStream(timeoutMillis, errorMsg);
+    }
+
+    public void requestEndOfStream() throws InterruptedException {
+      requestEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+    }
+
+    public void requestEndOfStream(long timeoutMillis) throws InterruptedException {
+      requestEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+    }
+
+    public void requestEndOfStream(String errorMsg) throws InterruptedException {
+      requestEndOfStream(env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public void requestEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+      request(1);
+      expectCompletion(timeoutMillis, errorMsg);
+    }
+
+    public List<T> requestNextElements(long elements) throws InterruptedException {
+      request(elements);
+      return nextElements(elements, env.defaultTimeoutMillis());
+    }
+
+    public List<T> requestNextElements(long elements, long timeoutMillis) throws InterruptedException {
+      request(elements);
+      return nextElements(elements, timeoutMillis, String.format("Did not receive %d expected elements", elements));
+    }
+
+    public List<T> requestNextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+      request(elements);
+      return nextElements(elements, timeoutMillis, errorMsg);
+    }
+
+    public T nextElement() throws InterruptedException {
+      return nextElement(env.defaultTimeoutMillis());
+    }
+
+    public T nextElement(long timeoutMillis) throws InterruptedException {
+      return nextElement(timeoutMillis, "Did not receive expected element");
+    }
+
+    public T nextElement(String errorMsg) throws InterruptedException {
+      return nextElement(env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+      return received.next(timeoutMillis, errorMsg);
+    }
+
+    public Optional<T> nextElementOrEndOfStream() throws InterruptedException {
+      return nextElementOrEndOfStream(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+    }
+
+    public Optional<T> nextElementOrEndOfStream(long timeoutMillis) throws InterruptedException {
+      return nextElementOrEndOfStream(timeoutMillis, "Did not receive expected stream completion");
+    }
+
+    public Optional<T> nextElementOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+      return received.nextOrEndOfStream(timeoutMillis, errorMsg);
+    }
+
+    public List<T> nextElements(long elements) throws InterruptedException {
+      return nextElements(elements, env.defaultTimeoutMillis(), "Did not receive expected element or completion");
+    }
+
+    public List<T> nextElements(long elements, String errorMsg) throws InterruptedException {
+      return nextElements(elements, env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public List<T> nextElements(long elements, long timeoutMillis) throws InterruptedException {
+      return nextElements(elements, timeoutMillis, "Did not receive expected element or completion");
+    }
+
+    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+      return received.nextN(elements, timeoutMillis, errorMsg);
+    }
+
+    public void expectNext(T expected) throws InterruptedException {
+      expectNext(expected, env.defaultTimeoutMillis());
+    }
+
+    public void expectNext(T expected, long timeoutMillis) throws InterruptedException {
+      T received = nextElement(timeoutMillis, "Did not receive expected element on downstream");
+      if (!received.equals(expected)) {
+        env.flop(String.format("Expected element %s on downstream but received %s", expected, received));
+      }
+    }
+
+    public void expectCompletion() throws InterruptedException {
+      expectCompletion(env.defaultTimeoutMillis(), "Did not receive expected stream completion");
+    }
+
+    public void expectCompletion(long timeoutMillis) throws InterruptedException {
+      expectCompletion(timeoutMillis, "Did not receive expected stream completion");
+    }
+
+    public void expectCompletion(String errorMsg) throws InterruptedException {
+      expectCompletion(env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+      received.expectCompletion(timeoutMillis, errorMsg);
+    }
+
+    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart) throws Exception {
+      expectErrorWithMessage(expected, Collections.singletonList(requiredMessagePart), env.defaultTimeoutMillis(), env.defaultPollTimeoutMillis());
+    }
+    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, List<String> requiredMessagePartAlternatives) throws Exception {
+      expectErrorWithMessage(expected, requiredMessagePartAlternatives, env.defaultTimeoutMillis(), env.defaultPollTimeoutMillis());
+    }
+
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, String requiredMessagePart, long timeoutMillis) throws Exception {
+      expectErrorWithMessage(expected, Collections.singletonList(requiredMessagePart), timeoutMillis);
+    }
+
+    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, List<String> requiredMessagePartAlternatives, long timeoutMillis) throws Exception {
+      expectErrorWithMessage(expected, requiredMessagePartAlternatives, timeoutMillis, timeoutMillis);
+    }
+
+    public <E extends Throwable> void expectErrorWithMessage(Class<E> expected, List<String> requiredMessagePartAlternatives,
+                                                             long totalTimeoutMillis, long pollTimeoutMillis) throws Exception {
+      final E err = expectError(expected, totalTimeoutMillis, pollTimeoutMillis);
+      final String message = err.getMessage();
+
+      boolean contains = false;
+      for (String requiredMessagePart : requiredMessagePartAlternatives)
+        if (message.contains(requiredMessagePart)) contains = true; // not short-circuting loop, it is expected to
+      assertTrue(contains,
+              String.format("Got expected exception [%s] but missing message part [%s], was: %s",
+                      err.getClass(), "anyOf: " + requiredMessagePartAlternatives, err.getMessage()));
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected) throws Exception {
+      return expectError(expected, env.defaultTimeoutMillis());
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis) throws Exception {
+      return expectError(expected, timeoutMillis, env.defaultPollTimeoutMillis());
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected, String errorMsg) throws Exception {
+      return expectError(expected, env.defaultTimeoutMillis(), errorMsg);
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected, long timeoutMillis, String errorMsg) throws Exception {
+      return expectError(expected, timeoutMillis, env.defaultPollTimeoutMillis(), errorMsg);
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected, long totalTimeoutMillis, long pollTimeoutMillis) throws Exception {
+      return expectError(expected, totalTimeoutMillis, pollTimeoutMillis, String.format("Expected onError(%s)", expected.getName()));
+    }
+
+    public <E extends Throwable> E expectError(Class<E> expected, long totalTimeoutMillis, long pollTimeoutMillis,
+                                               String errorMsg) throws Exception {
+      return received.expectError(expected, totalTimeoutMillis, pollTimeoutMillis, errorMsg);
+    }
+
+    public void expectNone() throws InterruptedException {
+      expectNone(env.defaultNoSignalsTimeoutMillis());
+    }
+
+    public void expectNone(String errMsgPrefix) throws InterruptedException {
+      expectNone(env.defaultNoSignalsTimeoutMillis(), errMsgPrefix);
+    }
+
+    public void expectNone(long withinMillis) throws InterruptedException {
+      expectNone(withinMillis, "Did not expect an element but got element");
+    }
+
+    public void expectNone(long withinMillis, String errMsgPrefix) throws InterruptedException {
+      received.expectNone(withinMillis, errMsgPrefix);
+    }
+
+  }
+
+  public static class ManualSubscriberWithSubscriptionSupport<T> extends ManualSubscriber<T> {
+
+    public ManualSubscriberWithSubscriptionSupport(TestEnvironment env) {
+      super(env);
+    }
+
+    @Override
+    public void onNext(T element) {
+      if (env.debugEnabled()) {
+        env.debug(String.format("%s::onNext(%s)", this, element));
+      }
+      if (subscription.isCompleted()) {
+        super.onNext(element);
+      } else {
+        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+      }
+    }
+
+    @Override
+    public void onComplete() {
+      if (env.debugEnabled()) {
+        env.debug(this + "::onComplete()");
+      }
+      if (subscription.isCompleted()) {
+        super.onComplete();
+      } else {
+        env.flop("Subscriber::onComplete() called before Subscriber::onSubscribe");
+      }
+    }
+
+    @Override
+    public void onSubscribe(Subscription s) {
+      if (env.debugEnabled()) {
+        env.debug(String.format("%s::onSubscribe(%s)", this, s));
+      }
+      if (!subscription.isCompleted()) {
+        subscription.complete(s);
+      } else {
+        env.flop("Subscriber::onSubscribe called on an already-subscribed Subscriber");
+      }
+    }
+
+    @Override
+    public void onError(Throwable cause) {
+      if (env.debugEnabled()) {
+        env.debug(String.format("%s::onError(%s)", this, cause));
+      }
+      if (subscription.isCompleted()) {
+        super.onError(cause);
+      } else {
+        env.flop(cause, String.format("Subscriber::onError(%s) called before Subscriber::onSubscribe", cause));
+      }
+    }
+  }
+
+  /**
+   * Similar to {@link org.reactivestreams.tck.TestEnvironment.ManualSubscriberWithSubscriptionSupport}
+   * but does not accumulate values signalled via <code>onNext</code>, thus it can not be used to assert
+   * values signalled to this subscriber. Instead it may be used to quickly drain a given publisher.
+   */
+  public static class BlackholeSubscriberWithSubscriptionSupport<T>
+    extends ManualSubscriberWithSubscriptionSupport<T> {
+
+    public BlackholeSubscriberWithSubscriptionSupport(TestEnvironment env) {
+      super(env);
+    }
+
+    @Override
+    public void onNext(T element) {
+      if (env.debugEnabled()) {
+        env.debug(String.format("%s::onNext(%s)", this, element));
+      }
+      if (!subscription.isCompleted()) {
+        env.flop(String.format("Subscriber::onNext(%s) called before Subscriber::onSubscribe", element));
+      }
+    }
+
+    @Override
+    public T nextElement(long timeoutMillis, String errorMsg) throws InterruptedException {
+      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+    }
+
+    @Override
+    public List<T> nextElements(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+      throw new RuntimeException("Can not expect elements from BlackholeSubscriber, use ManualSubscriber instead!");
+    }
+  }
+
+  public static class TestSubscriber<T> implements Subscriber<T> {
+    final Promise<Subscription> subscription;
+
+    protected final TestEnvironment env;
+
+    public TestSubscriber(TestEnvironment env) {
+      this.env = env;
+      subscription = new Promise<Subscription>(env);
+    }
+
+    @Override
+    public void onError(Throwable cause) {
+      env.flop(cause, String.format("Unexpected Subscriber::onError(%s)", cause));
+    }
+
+    @Override
+    public void onComplete() {
+      env.flop("Unexpected Subscriber::onComplete()");
+    }
+
+    @Override
+    public void onNext(T element) {
+      env.flop(String.format("Unexpected Subscriber::onNext(%s)", element));
+    }
+
+    @Override
+    public void onSubscribe(Subscription subscription) {
+      env.flop(String.format("Unexpected Subscriber::onSubscribe(%s)", subscription));
+    }
+
+    public void cancel() {
+      if (subscription.isCompleted()) {
+        subscription.value().cancel();
+      } else {
+        env.flop("Cannot cancel a subscription before having received it");
+      }
+    }
+  }
+
+  public static class ManualPublisher<T> implements Publisher<T> {
+    protected final TestEnvironment env;
+
+    protected long pendingDemand = 0L;
+    protected Promise<Subscriber<? super T>> subscriber;
+
+    protected final Receptacle<Long> requests;
+
+    protected final Latch cancelled;
+
+    public ManualPublisher(TestEnvironment env) {
+      this.env = env;
+      requests = new Receptacle<Long>(env);
+      cancelled = new Latch(env);
+      subscriber = new Promise<Subscriber<? super T>>(this.env);
+    }
+
+    @Override
+    public void subscribe(Subscriber<? super T> s) {
+      if (!subscriber.isCompleted()) {
+        subscriber.completeImmediatly(s);
+
+        Subscription subs = new Subscription() {
+          @Override
+          public void request(long elements) {
+            requests.add(elements);
+          }
+
+          @Override
+          public void cancel() {
+            cancelled.close();
+          }
+        };
+        s.onSubscribe(subs);
+
+      } else {
+        env.flop("TestPublisher doesn't support more than one Subscriber");
+      }
+    }
+
+    public void sendNext(T element) {
+      if (subscriber.isCompleted()) {
+        subscriber.value().onNext(element);
+      } else {
+        env.flop("Cannot sendNext before having a Subscriber");
+      }
+    }
+
+    public void sendCompletion() {
+      if (subscriber.isCompleted()) {
+        subscriber.value().onComplete();
+      } else {
+        env.flop("Cannot sendCompletion before having a Subscriber");
+      }
+    }
+
+    public void sendError(Throwable cause) {
+      if (subscriber.isCompleted()) {
+        subscriber.value().onError(cause);
+      } else {
+        env.flop("Cannot sendError before having a Subscriber");
+      }
+    }
+
+    public long expectRequest() throws InterruptedException {
+      return expectRequest(env.defaultTimeoutMillis());
+    }
+
+    public long expectRequest(long timeoutMillis) throws InterruptedException {
+      long requested = requests.next(timeoutMillis, "Did not receive expected `request` call");
+      if (requested <= 0) {
+        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+      } else {
+        pendingDemand += requested;
+        return requested;
+      }
+    }
+
+
+    public long expectRequest(long timeoutMillis, String errorMessageAddendum) throws InterruptedException {
+      long requested = requests.next(timeoutMillis, String.format("Did not receive expected `request` call. %s", errorMessageAddendum));
+      if (requested <= 0) {
+        return env.<Long>flopAndFail(String.format("Requests cannot be zero or negative but received request(%s)", requested));
+      } else {
+        pendingDemand += requested;
+        return requested;
+      }
+    }
+
+    public void expectExactRequest(long expected) throws InterruptedException {
+      expectExactRequest(expected, env.defaultTimeoutMillis());
+    }
+
+    public void expectExactRequest(long expected, long timeoutMillis) throws InterruptedException {
+      long requested = expectRequest(timeoutMillis);
+      if (requested != expected) {
+        env.flop(String.format("Received `request(%d)` on upstream but expected `request(%d)`", requested, expected));
+      }
+      pendingDemand += requested;
+    }
+
+    public void expectNoRequest() throws InterruptedException {
+      expectNoRequest(env.defaultTimeoutMillis());
+    }
+
+    public void expectNoRequest(long timeoutMillis) throws InterruptedException {
+      requests.expectNone(timeoutMillis, "Received an unexpected call to: request: ");
+    }
+
+    public void expectCancelling() throws InterruptedException {
+      expectCancelling(env.defaultTimeoutMillis());
+    }
+
+    public void expectCancelling(long timeoutMillis) throws InterruptedException {
+      cancelled.expectClose(timeoutMillis, "Did not receive expected cancelling of upstream subscription");
+    }
+
+    public boolean isCancelled() throws InterruptedException {
+      return cancelled.isClosed();
+    }
+  }
+
+  /**
+   * Like a CountDownLatch, but resettable and with some convenience methods
+   */
+  public static class Latch {
+    private final TestEnvironment env;
+    volatile private CountDownLatch countDownLatch = new CountDownLatch(1);
+
+    public Latch(TestEnvironment env) {
+      this.env = env;
+    }
+
+    public void reOpen() {
+      countDownLatch = new CountDownLatch(1);
+    }
+
+    public boolean isClosed() {
+      return countDownLatch.getCount() == 0;
+    }
+
+    public void close() {
+      countDownLatch.countDown();
+    }
+
+    public void assertClosed(String openErrorMsg) {
+      if (!isClosed()) {
+        env.flop(new ExpectedClosedLatchException(openErrorMsg));
+      }
+    }
+
+    public void assertOpen(String closedErrorMsg) {
+      if (isClosed()) {
+        env.flop(new ExpectedOpenLatchException(closedErrorMsg));
+      }
+    }
+
+    public void expectClose(String notClosedErrorMsg) throws InterruptedException {
+      expectClose(env.defaultTimeoutMillis(), notClosedErrorMsg);
+    }
+
+    public void expectClose(long timeoutMillis, String notClosedErrorMsg) throws InterruptedException {
+      countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+      if (countDownLatch.getCount() > 0) {
+        env.flop(String.format("%s within %d ms", notClosedErrorMsg, timeoutMillis));
+      }
+    }
+
+    static final class ExpectedOpenLatchException extends RuntimeException {
+      public ExpectedOpenLatchException(String message) {
+        super(message);
+      }
+    }
+
+    static final class ExpectedClosedLatchException extends RuntimeException {
+      public ExpectedClosedLatchException(String message) {
+        super(message);
+      }
+    }
+
+  }
+
+  // simple promise for *one* value, which cannot be reset
+  public static class Promise<T> {
+    private final TestEnvironment env;
+
+    public static <T> Promise<T> completed(TestEnvironment env, T value) {
+      Promise<T> promise = new Promise<T>(env);
+      promise.completeImmediatly(value);
+      return promise;
+    }
+
+    public Promise(TestEnvironment env) {
+      this.env = env;
+    }
+
+    private ArrayBlockingQueue<T> abq = new ArrayBlockingQueue<T>(1);
+    private AtomicReference<T> _value = new AtomicReference<T>();
+
+    public T value() {
+      final T value = _value.get();
+      if (value != null) {
+        return value;
+      } else {
+        env.flop("Cannot access promise value before completion");
+        return null;
+      }
+    }
+
+    public boolean isCompleted() {
+      return _value.get() != null;
+    }
+
+    /**
+     * Allows using expectCompletion to await for completion of the value and complete it _then_
+     */
+    public void complete(T value) {
+      if (_value.compareAndSet(null, value)) {
+        // we add the value to the queue such to wake up any expectCompletion which was triggered before complete() was called
+        abq.add(value);
+      } else {
+        env.flop(String.format("Cannot complete a promise more than once! Present value: %s, attempted to set: %s", _value.get(), value));
+      }
+    }
+
+    /**
+     * Same as complete.
+     *
+     * Keeping this method for binary compatibility.
+     */
+    public void completeImmediatly(T value) {
+      complete(value);
+    }
+
+    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+      if (!isCompleted()) {
+        T val = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+
+        if (val == null) {
+          env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+        }
+      }
+    }
+  }
+
+  // a "Promise" for multiple values, which also supports "end-of-stream reached"
+  public static class Receptacle<T> {
+    final int QUEUE_SIZE = 2 * TEST_BUFFER_SIZE;
+    private final TestEnvironment env;
+
+    private final ArrayBlockingQueue<Optional<T>> abq = new ArrayBlockingQueue<Optional<T>>(QUEUE_SIZE);
+
+    private final Latch completedLatch;
+
+    Receptacle(TestEnvironment env) {
+      this.env = env;
+      this.completedLatch = new Latch(env);
+    }
+
+    public void add(T value) {
+      completedLatch.assertOpen(String.format("Unexpected element %s received after stream completed", value));
+
+      abq.add(Optional.of(value));
+    }
+
+    public void complete() {
+      completedLatch.assertOpen("Unexpected additional complete signal received!");
+      completedLatch.close();
+
+      abq.add(Optional.<T>empty());
+    }
+
+    public T next(long timeoutMillis, String errorMsg) throws InterruptedException {
+      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+
+      if (value == null) {
+        return env.flopAndFail(String.format("%s within %d ms", errorMsg, timeoutMillis));
+      } else if (value.isDefined()) {
+        return value.get();
+      } else {
+        return env.flopAndFail("Expected element but got end-of-stream");
+      }
+    }
+
+    public Optional<T> nextOrEndOfStream(long timeoutMillis, String errorMsg) throws InterruptedException {
+      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+
+      if (value == null) {
+        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+        return Optional.empty();
+      }
+
+      return value;
+    }
+
+    /**
+     * @param timeoutMillis total timeout time for awaiting all {@code elements} number of elements
+     */
+    public List<T> nextN(long elements, long timeoutMillis, String errorMsg) throws InterruptedException {
+      List<T> result = new LinkedList<T>();
+      long remaining = elements;
+      long deadline = System.currentTimeMillis() + timeoutMillis;
+      while (remaining > 0) {
+        long remainingMillis = deadline - System.currentTimeMillis();
+
+        result.add(next(remainingMillis, errorMsg));
+        remaining--;
+      }
+
+      return result;
+    }
+
+
+    public void expectCompletion(long timeoutMillis, String errorMsg) throws InterruptedException {
+      Optional<T> value = abq.poll(timeoutMillis, TimeUnit.MILLISECONDS);
+
+      if (value == null) {
+        env.flop(String.format("%s within %d ms", errorMsg, timeoutMillis));
+      } else if (value.isDefined()) {
+        env.flop(String.format("Expected end-of-stream but got element [%s]", value.get()));
+      } // else, ok
+    }
+
+    /**
+     * @deprecated Deprecated in favor of {@link #expectError(Class, long, long, String)}.
+     */
+    @Deprecated
+    public <E extends Throwable> E expectError(Class<E> clazz, long timeoutMillis, String errorMsg) throws Exception {
+      return expectError(clazz, timeoutMillis, timeoutMillis, errorMsg);
+    }
+
+    @SuppressWarnings("unchecked")
+    final <E extends Throwable> E expectError(Class<E> clazz, final long totalTimeoutMillis,
+                                              long pollTimeoutMillis,
+                                              String errorMsg) throws Exception {
+      long totalTimeoutRemainingNs = MILLISECONDS.toNanos(totalTimeoutMillis);
+      long timeStampANs = System.nanoTime();
+      long timeStampBNs;
+
+      for (;;) {
+        Thread.sleep(Math.min(pollTimeoutMillis, NANOSECONDS.toMillis(totalTimeoutRemainingNs)));
+
+        if (env.asyncErrors.isEmpty()) {
+          timeStampBNs = System.nanoTime();
+          totalTimeoutRemainingNs =- timeStampBNs - timeStampANs;
+          timeStampANs = timeStampBNs;
+
+          if (totalTimeoutRemainingNs <= 0) {
+            return env.flopAndFail(String.format("%s within %d ms", errorMsg, totalTimeoutMillis));
+          }
+        } else {
+          // ok, there was an expected error
+          Throwable thrown = env.asyncErrors.remove(0);
+
+          if (clazz.isInstance(thrown)) {
+            return (E) thrown;
+          } else {
+
+            return env.flopAndFail(String.format("%s within %d ms; Got %s but expected %s",
+                    errorMsg, totalTimeoutMillis, thrown.getClass().getCanonicalName(), clazz.getCanonicalName()));
+          }
+        }
+      }
+    }
+
+    public void expectNone(long withinMillis, String errorMsgPrefix) throws InterruptedException {
+      Thread.sleep(withinMillis);
+      Optional<T> value = abq.poll();
+
+      if (value == null) {
+        // ok
+      } else if (value.isDefined()) {
+        env.flop(String.format("%s [%s]", errorMsgPrefix, value.get()));
+      } else {
+        env.flop("Expected no element but got end-of-stream");
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/WithHelperPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.tck.flow.support.Function;
+import org.reactivestreams.tck.flow.support.HelperPublisher;
+import org.reactivestreams.tck.flow.support.InfiniteHelperPublisher;
+
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Type which is able to create elements based on a seed {@code id} value.
+ * <p>
+ * Simplest implementations will simply return the incoming id as the element.
+ *
+ * @param <T> type of element to be delivered to the Subscriber
+ */
+public abstract class WithHelperPublisher<T> {
+
+  /** ExecutorService to be used by the provided helper {@link org.reactivestreams.Publisher} */
+  public abstract ExecutorService publisherExecutorService();
+
+  /**
+   * 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 {@code element} element.
+   * <p>
+   * 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 {@code element} as payload of your custom element, such as appending it to a String or other identifier.
+   * <p>
+   * <b>Warning:</b> This method may be called concurrently by the helper publisher, thus it should be implemented in a
+   * thread-safe manner.
+   *
+   * @return element of the matching type {@code T} that will be delivered to the tested Subscriber
+   */
+  public abstract T createElement(int element);
+
+  /**
+   * Helper method required for creating the Publisher to which the tested Subscriber will be subscribed and tested against.
+   * <p>
+   * By default an <b>asynchronously signalling Publisher</b> is provided, which will use {@link #createElement(int)}
+   * to generate elements type your Subscriber is able to consume.
+   * <p>
+   * 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 {@code elements} parameter) and MUST also must treat the following numbers of elements in these specific ways:
+   * <ul>
+   *   <li>
+   *     If {@code elements} is {@code Long.MAX_VALUE} the produced stream must be infinite.
+   *   </li>
+   *   <li>
+   *     If {@code elements} is {@code 0} the {@code Publisher} should signal {@code onComplete} immediatly.
+   *     In other words, it should represent a "completed stream".
+   *   </li>
+   * </ul>
+   */
+  @SuppressWarnings("unchecked")
+  public Publisher<T> createHelperPublisher(long elements) {
+    final Function<Integer, T> mkElement = new Function<Integer, T>() {
+      @Override public T apply(Integer id) throws Throwable {
+        return createElement(id);
+      }
+    };
+
+    if (elements > Integer.MAX_VALUE) return new InfiniteHelperPublisher(mkElement, publisherExecutorService());
+    else return new HelperPublisher(0, (int) elements, mkElement, publisherExecutorService());
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/FlowPublisherVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.FlowAdapters;
+import org.reactivestreams.tck.PublisherVerification;
+import org.reactivestreams.tck.TestEnvironment;
+
+import java.util.concurrent.Flow;
+
+/**
+ * Provides tests for verifying a Java 9+ {@link java.util.concurrent.Flow.Publisher} specification rules.
+ *
+ * @see java.util.concurrent.Flow.Publisher
+ */
+public abstract class FlowPublisherVerification<T> extends PublisherVerification<T> {
+
+  public FlowPublisherVerification(TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+    super(env, publisherReferenceGCTimeoutMillis);
+  }
+
+  public FlowPublisherVerification(TestEnvironment env) {
+    super(env);
+  }
+
+  @Override
+  final public Publisher<T> createPublisher(long elements) {
+    final Flow.Publisher<T> flowPublisher = createFlowPublisher(elements);
+    return FlowAdapters.toPublisher(flowPublisher);
+  }
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a Publisher for a stream with exactly the given number of elements.
+   * If `elements` is `Long.MAX_VALUE` the produced stream must be infinite.
+   */
+  public abstract Flow.Publisher<T> createFlowPublisher(long elements);
+
+  @Override
+  final public Publisher<T> createFailedPublisher() {
+    final Flow.Publisher<T> failed = createFailedFlowPublisher();
+    if (failed == null) return null; // because `null` means "SKIP" in createFailedPublisher
+    else return FlowAdapters.toPublisher(failed);
+  }
+  /**
+   * By implementing this method, additional TCK tests concerning a "failed" publishers will be run.
+   *
+   * The expected behaviour of the {@link Flow.Publisher} returned by this method is hand out a subscription,
+   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+   *
+   * If you ignore these additional tests, return {@code null} from this method.
+   */
+  public abstract Flow.Publisher<T> createFailedFlowPublisher();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/FlowSubscriberBlackboxVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow;
+
+import org.reactivestreams.FlowAdapters;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.reactivestreams.tck.SubscriberBlackboxVerification;
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.support.SubscriberBlackboxVerificationRules;
+
+import java.util.concurrent.Flow;
+
+/**
+ * Provides tests for verifying {@link java.util.concurrent.Flow.Subscriber} and {@link java.util.concurrent.Flow.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 {@code org.reactivestreams.tck.SubscriberWhiteboxVerification}
+ * instead.
+ *
+ * @see java.util.concurrent.Flow.Subscriber
+ * @see java.util.concurrent.Flow.Subscription
+ */
+public abstract class FlowSubscriberBlackboxVerification<T> extends SubscriberBlackboxVerification<T>
+  implements SubscriberBlackboxVerificationRules {
+
+  protected FlowSubscriberBlackboxVerification(TestEnvironment env) {
+    super(env);
+  }
+
+  @Override
+  public final void triggerRequest(Subscriber<? super T> subscriber) {
+    triggerFlowRequest(FlowAdapters.toFlowSubscriber(subscriber));
+  }
+  /**
+   * Override this method if the {@link java.util.concurrent.Flow.Subscriber} implementation you are verifying
+   * needs an external signal before it signals demand to its Publisher.
+   *
+   * By default this method does nothing.
+   */
+  public void triggerFlowRequest(Flow.Subscriber<? super T> subscriber) {
+    // this method is intentionally left blank
+  }
+
+  @Override
+  public final Subscriber<T> createSubscriber() {
+    return FlowAdapters.<T>toSubscriber(createFlowSubscriber());
+  }
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a new {@link Flow.Subscriber} instance to be subjected to the testing logic.
+   */
+  abstract public Flow.Subscriber<T> createFlowSubscriber();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/FlowSubscriberWhiteboxVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow;
+
+import org.reactivestreams.FlowAdapters;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.tck.SubscriberWhiteboxVerification;
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.support.SubscriberWhiteboxVerificationRules;
+
+import java.util.concurrent.Flow;
+
+/**
+ * Provides whitebox style tests for verifying {@link java.util.concurrent.Flow.Subscriber}
+ * and {@link java.util.concurrent.Flow.Subscription} specification rules.
+ *
+ * @see java.util.concurrent.Flow.Subscriber
+ * @see java.util.concurrent.Flow.Subscription
+ */
+public abstract class FlowSubscriberWhiteboxVerification<T> extends SubscriberWhiteboxVerification<T>
+  implements SubscriberWhiteboxVerificationRules {
+
+  protected FlowSubscriberWhiteboxVerification(TestEnvironment env) {
+    super(env);
+  }
+
+  @Override
+  final public Subscriber<T> createSubscriber(WhiteboxSubscriberProbe<T> probe) {
+    return FlowAdapters.toSubscriber(createFlowSubscriber(probe));
+  }
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a new {@link org.reactivestreams.Subscriber} instance to be subjected to the testing logic.
+   *
+   * In order to be meaningfully testable your Subscriber must inform the given
+   * `WhiteboxSubscriberProbe` of the respective events having been received.
+   */
+  protected abstract Flow.Subscriber<T> createFlowSubscriber(WhiteboxSubscriberProbe<T> probe);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/IdentityFlowProcessorVerification.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow;
+
+import org.reactivestreams.*;
+import org.reactivestreams.tck.IdentityProcessorVerification;
+import org.reactivestreams.tck.TestEnvironment;
+import org.reactivestreams.tck.flow.support.SubscriberWhiteboxVerificationRules;
+import org.reactivestreams.tck.flow.support.PublisherVerificationRules;
+
+import java.util.concurrent.Flow;
+
+public abstract class IdentityFlowProcessorVerification<T> extends IdentityProcessorVerification<T>
+  implements SubscriberWhiteboxVerificationRules, PublisherVerificationRules {
+
+  public IdentityFlowProcessorVerification(TestEnvironment env) {
+    super(env);
+  }
+
+  public IdentityFlowProcessorVerification(TestEnvironment env, long publisherReferenceGCTimeoutMillis) {
+    super(env, publisherReferenceGCTimeoutMillis);
+  }
+
+  public IdentityFlowProcessorVerification(TestEnvironment env, long publisherReferenceGCTimeoutMillis, int processorBufferSize) {
+    super(env, publisherReferenceGCTimeoutMillis, processorBufferSize);
+  }
+
+  /**
+   * By implementing this method, additional TCK tests concerning a "failed" Flow publishers will be run.
+   *
+   * The expected behaviour of the {@link Flow.Publisher} returned by this method is hand out a subscription,
+   * followed by signalling {@code onError} on it, as specified by Rule 1.9.
+   *
+   * If you want to ignore these additional tests, return {@code null} from this method.
+   */
+  protected abstract Flow.Publisher<T> createFailedFlowPublisher();
+
+  /**
+   * This is the main method you must implement in your test incarnation.
+   * It must create a {@link Flow.Processor}, which simply forwards all stream elements from its upstream
+   * to its downstream. It must be able to internally buffer the given number of elements.
+   *
+   * @param bufferSize number of elements the processor is required to be able to buffer.
+   */
+  protected abstract Flow.Processor<T,T> createIdentityFlowProcessor(int bufferSize);
+
+  @Override
+  public final Processor<T, T> createIdentityProcessor(int bufferSize) {
+    return FlowAdapters.toProcessor(createIdentityFlowProcessor(bufferSize));
+  }
+
+  @Override
+  public final Publisher<T> createFailedPublisher() {
+    Flow.Publisher<T> failed = createFailedFlowPublisher();
+    if (failed == null) return null; // because `null` means "SKIP" in createFailedPublisher
+    else return FlowAdapters.toPublisher(failed);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/Function.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+public interface Function<In, Out> {
+  public Out apply(In in) throws Throwable;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/HelperPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+
+import org.reactivestreams.example.unicast.AsyncIterablePublisher;
+
+public class HelperPublisher<T> extends AsyncIterablePublisher<T> {
+
+    public HelperPublisher(final int from, final int to, final Function<Integer, T> create, final Executor executor) {
+        super(new Iterable<T>() {
+          { if(from > to) throw new IllegalArgumentException("from must be equal or greater than to!"); }
+          @Override public Iterator<T> iterator() {
+            return new Iterator<T>() {
+              private int at = from;
+              @Override public boolean hasNext() { return at < to; }
+              @Override public T next() {
+                if (!hasNext()) return Collections.<T>emptyList().iterator().next();
+                else try {
+                  return create.apply(at++);
+                } catch (Throwable t) {
+                  throw new IllegalStateException(String.format("Failed to create element for id %d!", at - 1), t);
+                }
+              }
+              @Override public void remove() { throw new UnsupportedOperationException(); }
+            };
+          }
+        }, executor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/InfiniteHelperPublisher.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+import org.reactivestreams.example.unicast.AsyncIterablePublisher;
+
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+
+public class InfiniteHelperPublisher<T> extends AsyncIterablePublisher<T> {
+
+    public InfiniteHelperPublisher(final Function<Integer, T> create, final Executor executor) {
+        super(new Iterable<T>() {
+          @Override public Iterator<T> iterator() {
+            return new Iterator<T>() {
+              private int at = 0;
+
+              @Override public boolean hasNext() { return true; }
+              @Override public T next() {
+                try {
+                  return create.apply(at++); // Wraps around on overflow
+                } catch (Throwable t) {
+                  throw new IllegalStateException(
+                    String.format("Failed to create element in %s for id %s!", getClass().getSimpleName(), at - 1), t);
+                }
+              }
+              @Override public void remove() { throw new UnsupportedOperationException(); }
+            };
+          }
+        }, executor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/NonFatal.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+
+/**
+ * Copy of scala.control.util.NonFatal in order to not depend on scala-library
+ */
+public class NonFatal {
+  private NonFatal() {
+    // no instances, please.
+  }
+
+  /**
+   * Returns true if the provided `Throwable` is to be considered non-fatal, or false if it is to be considered fatal
+   *
+   * @param t throwable to be matched for fatal-ness
+   * @return true if is a non-fatal throwable, false otherwise
+   */
+  public static boolean isNonFatal(Throwable t) {
+    if (t instanceof StackOverflowError) {
+      // StackOverflowError ok even though it is a VirtualMachineError
+      return true;
+    } else if (t instanceof VirtualMachineError ||
+        t instanceof ThreadDeath ||
+        t instanceof InterruptedException ||
+        t instanceof LinkageError) {
+      // VirtualMachineError includes OutOfMemoryError and other fatal errors
+      return false;
+    } else {
+      return true;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/Optional.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+import java.util.NoSuchElementException;
+
+// simplest possible version of Scala's Option type
+public abstract class Optional<T> {
+
+  private static final Optional<Object> NONE = new Optional<Object>() {
+    @Override
+    public Object get() {
+      throw new NoSuchElementException(".get call on None!");
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return true;
+    }
+  };
+
+  private Optional() {
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> Optional<T> empty() {
+    return (Optional<T>) NONE;
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> Optional<T> of(T it) {
+    if (it == null) return (Optional<T>) Optional.NONE;
+    else return new Some(it);
+  }
+
+  public abstract T get();
+
+  public abstract boolean isEmpty();
+
+  public boolean isDefined() {
+    return !isEmpty();
+  }
+
+  public static class Some<T> extends Optional<T> {
+    private final T value;
+
+    Some(T value) {
+      this.value = value;
+    }
+
+    @Override
+    public T get() {
+      return value;
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return false;
+    }
+
+    @Override
+    public String toString() {
+      return String.format("Some(%s)", value);
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "None";
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/PublisherVerificationRules.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+/**
+ * Internal TCK use only.
+ * Add / Remove tests for PublisherVerification here to make sure that they arre added/removed in the other places.
+ */
+public interface PublisherVerificationRules {
+  /**
+   * Validates that the override of {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()}
+   * returns a non-negative value.
+   */
+  void required_validate_maxElementsFromPublisher() throws Exception;
+  /**
+   * Validates that the override of {@link org.reactivestreams.tck.PublisherVerification#boundedDepthOfOnNextAndRequestRecursion()}
+   * returns a positive value.
+   */
+  void required_validate_boundedDepthOfOnNextAndRequestRecursion() throws Exception;
+  /**
+   * Asks for a {@code Publisher} that should emit exactly one item and complete (both within a
+   * timeout specified by {@link org.reactivestreams.tck.TestEnvironment#defaultTimeoutMillis()})
+   * in response to a request(1).
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} returns zero.
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code Publisher.subscribe(Subscriber)} method has actual implementation,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, if there is an upstream {@code Publisher},
+   * that {@code Publisher} is actually subscribed to,</li>
+   * <li>if the {@code Publisher} is part of a chain, all elements actually issue a {@code request()} call
+   * in response to the test subscriber or by default to their upstream,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, the {@code Subscriber.onSubscribe} is called
+   * as part of the preparation process (usually before subscribing to other {@code Publisher}s),</li>
+   * <li>if the {@code Publisher} implementation works for a consumer that calls {@code request(1)},</li>
+   * <li>if the {@code Publisher} implementation is able to emit an {@code onComplete} without requests,</li>
+   * <li>that the {@code Publisher} implementation does not emit more than the allowed elements (exactly one).</li>
+   * </ul>
+   */
+  void required_createPublisher1MustProduceAStreamOfExactly1Element() throws Throwable;
+  /**
+   * Asks for a {@code Publisher} that should emit exactly three items and complete (all within a
+   * timeout specified by {@link org.reactivestreams.tck.TestEnvironment#defaultTimeoutMillis()}).
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * The tests requests one-by-one and verifies each single response item arrives in time.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code Publisher.subscribe(Subscriber)} method has actual implementation,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, if there is an upstream {@code Publisher},
+   * that {@code Publisher} is actually subscribed to,</li>
+   * <li>if the {@code Publisher} is part of a chain, all elements actually issue a {@code request()} call
+   * in response to the test subscriber or by default to their upstream,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, the {@code Subscriber.onSubscribe} is called
+   * as part of the preparation process (usually before subscribing to other {@code Publisher}s),</li>
+   * <li>if the {@code Publisher} implementation works for a subscriber that calls {@code request(1)} after consuming an item,</li>
+   * <li>if the {@code Publisher} implementation is able to emit an {@code onComplete} without requests.</li>
+   * </ul>
+   */
+  void required_createPublisher3MustProduceAStreamOfExactly3Elements() throws Throwable;
+  /**
+   * Asks for a {@code Publisher} that responds to a request pattern of 0 (not requesting upfront), 1, 1 and 2
+   * in a timely manner.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.1'>1.1</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 5.
+   * <p>
+   * This test ensures that the {@code Publisher} implementation correctly responds to {@code request()} calls that in
+   * total are less than the number of elements this {@code Publisher} could emit (thus the completion event won't be emitted).
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void required_spec101_subscriptionRequestMustResultInTheCorrectNumberOfProducedElements() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} and verifies that requesting once and with more than the length (but bounded) results in the
+   * correct number of items to be emitted (i.e., length 3 and request 10) followed by an {@code onComplete} signal.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.2'>1.2</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * This test ensures that the {@code Publisher} implementation can deal with larger requests than the number of items it can produce.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass.</li>
+   * </ul>
+   */
+  void required_spec102_maySignalLessThanRequestedAndTerminateSubscription() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (i.e., length 10), repeatedly subscribes to this {@code Publisher}, requests items
+   * one by one and verifies the {@code Publisher} calls the {@code onXXX} methods non-overlappingly.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.3'>1.3</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 10.
+   * <p>
+   * Note that this test is probabilistic, that is, may not capture any concurrent invocation in a {code Publisher} implementation.
+   * Note also that this test is sensitive to cases when a {@code request()} call in {@code onSubscribe()} triggers an asynchronous
+   * call to the other {@code onXXX} methods. In contrast, the test allows synchronous call chain of
+   * {@code onSubscribe -> request -> onNext}.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if a {@code request()} call from {@code onSubscribe()} could trigger an asynchronous call to {@code onNext()} and if so, make sure
+   * such {@code request()} calls are deferred until the call to {@code onSubscribe()} returns normally.</li>
+   * </ul>
+   */
+  void stochastic_spec103_mustSignalOnMethodsSequentially() throws Throwable;
+  /**
+   * Asks for an error {@code Publisher} that should call {@code onSubscribe} exactly once
+   * followed by a single call to {@code onError()} without receiving any requests and otherwise
+   * not throwing any exception.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.4'>1.4</a>
+   * <p>
+   * The test is not executed if {@code PublisherVerification.createErrorPublisher()} returns null.
+   * <p>
+   * If this test fails, the following could be checked within the error {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code Publisher.subscribe(Subscriber)} method has actual implementation,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, if there is an upstream {@code Publisher},
+   * that {@code Publisher} is actually subscribed to,</li>
+   * <li>if the {@code Publisher} implementation does signal an {@code onSubscribe} before signalling {@code onError},</li>
+   * <li>if the {@code Publisher} implementation is able to emit an {@code onError} without requests,</li>
+   * <li>if the {@code Publisher} is non-empty as this test requires a {@code Publisher} to signal an
+   * {@code onError} eagerly.</li>
+   * </ul>
+   */
+  void optional_spec104_mustSignalOnErrorWhenFails() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (i.e., length 3) and verifies, after requesting one by one, the sequence
+   * completes normally.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.5'>1.5</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * Note that the tests requests 1 after the items have been received and before expecting an {@code onComplete} signal.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * </ul>
+   */
+  void required_spec105_mustSignalOnCompleteWhenFiniteStreamTerminates() throws Throwable;
+  /**
+   * Asks for an empty {@code Publisher} (i.e., length 0) and verifies it completes in a timely manner.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.5'>1.5</a>
+   * <p>
+   * Note that the tests requests 1 before expecting an {@code onComplete} signal.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>if the {@code Publisher} is non-empty as this test requires a {@code Publisher} without items.</li>
+   * </ul>
+   */
+  void optional_spec105_emptyStreamMustTerminateBySignallingOnComplete() throws Throwable;
+  /**
+   * Currently, this test is skipped because it is unclear this rule can be effectively checked
+   * on a {@code Publisher} instance without looking into or hooking into the implementation of it.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.6'>1.6</a>
+   */
+  void untested_spec106_mustConsiderSubscriptionCancelledAfterOnErrorOrOnCompleteHasBeenCalled() throws Throwable;
+  /**
+   * Asks for a single-element {@code Publisher} and checks if requesting after the terminal event doesn't
+   * lead to more items or terminal signals to be emitted.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.7'>1.7</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 1.
+   * <p>
+   * The tests requests more items than the expected {@code Publisher} length upfront and some more items after its completion.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>the indication for the terminal state is properly persisted and a request call can't trigger emission of more items or another
+   * terminal signal.</li>
+   * </ul>
+   */
+  void required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled() throws Throwable;
+  /**
+   * Currently, this test is skipped, although it is possible to validate an error {@code Publisher} along
+   * the same lines as {@link #required_spec107_mustNotEmitFurtherSignalsOnceOnCompleteHasBeenSignalled()}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.7'>1.7</a>
+   */
+  void untested_spec107_mustNotEmitFurtherSignalsOnceOnErrorHasBeenSignalled() throws Throwable;
+  /**
+   * Currently, this test is skipped because there was no agreement on how to verify its "eventually" requirement.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.8'>1.8</a>
+   */
+  void untested_spec108_possiblyCanceledSubscriptionShouldNotReceiveOnErrorOrOnCompleteSignals() throws Throwable;
+  /**
+   * Asks for an empty {@code Publisher} and verifies if {@code onSubscribe} signal was emitted before
+   * any other {@code onNext}, {@code onError} or {@code onComplete} signal.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.9'>1.9</a>
+   * <p>
+   * Note that this test doesn't request anything, however, an {@code onNext} is not considered as a failure.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>the {@code Publisher.subscribe(Subscriber)} method has actual implementation,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, if there is an upstream {@code Publisher},
+   * that {@code Publisher} is actually subscribed to,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, the {@code Subscriber.onSubscribe} is called
+   * as part of the preparation process (usually before subscribing to other {@code Publisher}s).</li>
+   * </ul>
+   */
+  void required_spec109_mustIssueOnSubscribeForNonNullSubscriber() throws Throwable;
+  /**
+   * Currently, this test is skipped because there is no common agreement on what is to be considered a fatal exception and
+   * besides, {@code Publisher.subscribe} is only allowed throw a {@code NullPointerException} and any other
+   * exception would require looking into or hooking into the implementation of the {@code Publisher}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.9'>1.9</a>
+   */
+  void untested_spec109_subscribeShouldNotThrowNonFatalThrowable() throws Throwable;
+  /**
+   * Asks for an empty {@code Publisher} and calls {@code subscribe} on it with {@code null} that should result in
+   * a {@code NullPointerException} to be thrown.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.9'>1.9</a>
+   * <p>
+   * If this test fails, check if the {@code subscribe()} implementation has an explicit null check (or a method dereference
+   * on the {@code Subscriber}), especially if the incoming {@code Subscriber} is wrapped or stored to be used later.
+   */
+  void required_spec109_subscribeThrowNPEOnNullSubscriber() throws Throwable;
+  /**
+   * Asks for an error {@code Publisher} that should call {@code onSubscribe} exactly once
+   * followed by a single call to {@code onError()} without receiving any requests.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.9'>1.9</a>
+   * <p>
+   * The test is not executed if {@code PublisherVerification.createErrorPublisher()} returns null.
+   * <p>
+   * The difference between this test and {@link #optional_spec104_mustSignalOnErrorWhenFails()} is that there is
+   * no explicit verification if exceptions were thrown in addition to the regular {@code onSubscribe+onError} signal pair.
+   * <p>
+   * If this test fails, the following could be checked within the error {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code Publisher.subscribe(Subscriber)} method has actual implementation,</li>
+   * <li>in the {@code Publisher.subscribe(Subscriber)} method, if there is an upstream {@code Publisher},
+   * that {@code Publisher} is actually subscribed to,</li>
+   * <li>if the {@code Publisher} implementation is able to emit an {@code onError} without requests,</li>
+   * <li>if the {@code Publisher} is non-empty as this test expects a {@code Publisher} without items.</li>
+   * </ul>
+   */
+  void required_spec109_mayRejectCallsToSubscribeIfPublisherIsUnableOrUnwillingToServeThemRejectionMustTriggerOnErrorAfterOnSubscribe() throws Throwable;
+  /**
+   * Currently, this test is skipped because enforcing rule §1.10 requires unlimited retention and reference-equal checks on
+   * all incoming {@code Subscriber} which is generally infeasible, plus reusing the same {@code Subscriber} instance is
+   * better detected (or ignored) inside {@code Subscriber.onSubscribe} when the method is called multiple times.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.10'>1.10</a>
+   */
+  void untested_spec110_rejectASubscriptionRequestIfTheSameSubscriberSubscribesTwice() throws Throwable;
+  /**
+   * Asks for a single-element {@code Publisher} and subscribes to it twice, without consuming with either
+   * {@code Subscriber} instance
+   * (i.e., no requests are issued).
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.11'>1.11</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 1.
+   * <p>
+   * Note that this test ignores what signals the {@code Publisher} emits. Any exception thrown through non-regular
+   * means will indicate a skipped test.
+   */
+  void optional_spec111_maySupportMultiSubscribe() throws Throwable;
+  /**
+   * Asks for a single-element {@code Publisher} and subscribes to it twice.
+   * Each {@code Subscriber} requests for 1 element and checks if onNext or onComplete signals was received.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.11'>1.11</a>,
+   * and depends on valid implementation of rule <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.5'>1.5</a>
+   * in order to verify this.
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 1.
+   * <p>
+   * Any exception thrown through non-regular means will indicate a skipped test.
+   */
+  void optional_spec111_registeredSubscribersMustReceiveOnNextOrOnCompleteSignals() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 5), subscribes 3 {@code Subscriber}s to it, requests with different
+   * patterns and checks if all 3 received the same events in the same order.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.11'>1.11</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 5.
+   * <p>
+   * The request pattern for the first {@code Subscriber} is (1, 1, 2, 1); for the second is (2, 3) and for the third is (3, 1, 1).
+   * <p>
+   * Note that this test requires a {@code Publisher} that always emits the same signals to any {@code Subscriber}, regardless of
+   * when they subscribe and how they request elements. I.e., a "live" {@code Publisher} emitting the current time would not pass this test.
+   * <p>
+   * Note that this test is optional and may appear skipped even if the behavior should be actually supported by the {@code Publisher},
+   * see the skip message for an indication of this.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingOneByOne() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 3), subscribes 3 {@code Subscriber}s to it, requests more than the length items
+   * upfront with each and verifies they all received the same items in the same order (but does not verify they all complete).
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.11'>1.11</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * Note that this test requires a {@code Publisher} that always emits the same signals to any {@code Subscriber}, regardless of
+   * when they subscribe and how they request elements. I.e., a "live" {@code Publisher} emitting the current time would not pass this test.
+   * <p>
+   * Note that this test is optional and may appear skipped even if the behavior should be actually supported by the {@code Publisher},
+   * see the skip message for an indication of this.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfront() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 3), subscribes 3 {@code Subscriber}s to it, requests more than the length items
+   * upfront with each and verifies they all received the same items in the same order followed by an {@code onComplete} signal.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#1.11'>1.11</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * Note that this test requires a {@code Publisher} that always emits the same signals to any {@code Subscriber}, regardless of
+   * when they subscribe and how they request elements. I.e., a "live" {@code Publisher} emitting the current time would not pass this test.
+   * <p>
+   * Note that this test is optional and may appear skipped even if the behavior should be actually supported by the {@code Publisher},
+   * see the skip message for an indication of this.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void optional_spec111_multicast_mustProduceTheSameElementsInTheSameSequenceToAllOfItsSubscribersWhenRequestingManyUpfrontAndCompleteAsExpected() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 6), requests several times from within {@code onSubscribe} and then requests
+   * one-by-one from {@code onNext}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.2'>3.2</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 6.
+   * <p>
+   * The request pattern is 3 x 1 from within {@code onSubscribe} and one from within each {@code onNext} invocation.
+   * <p>
+   * The test consumes the {@code Publisher} but otherwise doesn't verify the {@code Publisher} completes (however, it checks
+   * for errors).
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void required_spec302_mustAllowSynchronousRequestCallsFromOnNextAndOnSubscribe() throws Throwable;
+  /**
+   * Asks for a {@code Publisher} with length equal to the value returned by {@link #required_validate_boundedDepthOfOnNextAndRequestRecursion()} plus 1,
+   * calls {@code request(1)} externally and then from within {@code onNext} and checks if the stack depth did not increase beyond the
+   * amount permitted by {@link #required_validate_boundedDepthOfOnNextAndRequestRecursion()}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.3'>3.3</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than
+   * {@link #required_validate_boundedDepthOfOnNextAndRequestRecursion()} plus 1.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the implementation doesn't allow unbounded recursion when {@code request()} is called from within {@code onNext}, i.e., the lack of
+   * reentrant-safe state machine around the request amount (such as a for loop with a bound on the parameter {@code n} that calls {@code onNext}).
+   * </ul>
+   */
+  void required_spec303_mustNotAllowUnboundedRecursion() throws Throwable;
+  /**
+   * Currently, this test is skipped because a {@code request} could enter into a synchronous computation via {@code onNext}
+   * legally and otherwise there is no common agreement how to detect such heavy computation reliably.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.4'>3.4</a>
+   */
+  void untested_spec304_requestShouldNotPerformHeavyComputations() throws Exception;
+  /**
+   * Currently, this test is skipped because there is no reliable agreed upon way to detect a heavy computation.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.5'>3.5</a>
+   */
+  void untested_spec305_cancelMustNotSynchronouslyPerformHeavyComputation() throws Exception;
+  /**
+   * Asks for a short {@code Publisher} (length 3) and verifies that cancelling without requesting anything, then requesting
+   * items should result in no signals to be emitted.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.6'>3.6</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * The post-cancellation request pattern is (1, 1, 1).
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the cancellation indicator flag is properly persisted (may require volatile) and checked as part of the signal emission process.</li>
+   * </ul>
+   */
+  void required_spec306_afterSubscriptionIsCancelledRequestMustBeNops() throws Throwable;
+  /**
+   * Asks for a single-element {@code Publisher} and verifies that without requesting anything, cancelling the sequence
+   * multiple times should result in no signals to be emitted and should result in an thrown exception.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.7'>3.7</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 1.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the cancellation indicator flag is properly persisted (may require volatile) and checked as part of the signal emission process.</li>
+   * </ul>
+   */
+  void required_spec307_afterSubscriptionIsCancelledAdditionalCancelationsMustBeNops() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 10) and issues a {@code request(0)} which should trigger an {@code onError} call
+   * with an {@code IllegalArgumentException}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.9'>3.9</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 10.
+   * <p>
+   * Note that this test expects the {@code IllegalArgumentException} being signalled through {@code onError}, not by
+   * throwing from {@code request()} (which is also forbidden) or signalling the error by any other means (i.e., through the
+   * {@code Thread.currentThread().getUncaughtExceptionHandler()} for example).
+   * <p>
+   * Note also that requesting and emission may happen concurrently and honoring this rule may require extra coordination within
+   * the {@code Publisher}.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the {@code Publisher} can emit an {@code onError} in this particular case, even if there was no prior and legal
+   * {@code request} call and even if the {@code Publisher} would like to emit items first before emitting an {@code onError}
+   * in general.
+   * </ul>
+   */
+  void required_spec309_requestZeroMustSignalIllegalArgumentException() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 10) and issues a random, negative {@code request()} call which should
+   * trigger an {@code onError} call with an {@code IllegalArgumentException}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.9'>3.9</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 10.
+   * <p>
+   * Note that this test expects the {@code IllegalArgumentException} being signalled through {@code onError}, not by
+   * throwing from {@code request()} (which is also forbidden) or signalling the error by any other means (i.e., through the
+   * {@code Thread.currentThread().getUncaughtExceptionHandler()} for example).
+   * <p>
+   * Note also that requesting and emission may happen concurrently and honoring this rule may require extra coordination within
+   * the {@code Publisher}.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the {@code Publisher} can emit an {@code onError} in this particular case, even if there was no prior and legal
+   * {@code request} call and even if the {@code Publisher} would like to emit items first before emitting an {@code onError}
+   * in general.
+   * </ul>
+   */
+  void required_spec309_requestNegativeNumberMustSignalIllegalArgumentException() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 10) and issues a random, negative {@code request()} call which should
+   * trigger an {@code onError} call with an {@code IllegalArgumentException}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.9'>3.9</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 10.
+   * <p>
+   * Note that this test expects the {@code IllegalArgumentException} being signalled through {@code onError}, not by
+   * throwing from {@code request()} (which is also forbidden) or signalling the error by any other means (i.e., through the
+   * {@code Thread.currentThread().getUncaughtExceptionHandler()} for example).
+   * <p>
+   * Note also that requesting and emission may happen concurrently and honoring this rule may require extra coordination within
+   * the {@code Publisher}.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the {@code Publisher} can emit an {@code onError} in this particular case, even if there was no prior and legal
+   * {@code request} call and even if the {@code Publisher} would like to emit items first before emitting an {@code onError}
+   * in general.
+   * </ul>
+   */
+  void optional_spec309_requestNegativeNumberMaySignalIllegalArgumentExceptionWithSpecificMessage() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 20), requests some items (less than the length), consumes one item then
+   * cancels the sequence and verifies the publisher emitted at most the requested amount and stopped emitting (or terminated).
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.12'>3.12</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 20.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the cancellation indicator flag is properly persisted (may require volatile) and checked as part of the signal emission process.</li>
+   * </ul>
+   */
+  void required_spec312_cancelMustMakeThePublisherToEventuallyStopSignaling() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 3) requests and consumes one element from it, cancels the {@code Subscription}
+   * , calls {@code System.gc()} and then checks if all references to the test {@code Subscriber} has been dropped (by checking
+   * the {@code WeakReference} has been emptied).
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.13'>3.13</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>the cancellation indicator flag is properly persisted (may require volatile) and checked as part of the signal emission process.</li>
+   * <li>the {@code Publisher} stores the {@code Subscriber} reference somewhere which is then not cleaned up when the {@code Subscriber} is cancelled.
+   * Note that this may happen on many code paths in a {@code Publisher}, for example in an emission loop that terminates because of the
+   * {@code cancel} signal or because reaching a terminal state. Note also that eagerly nulling {@code Subscriber} references may not be necessary
+   * for this test to pass in case there is a self-contained chain of them (i.e., {@code Publisher.subscribe()} creates a chain of fresh
+   * {@code Subscriber} instances where each of them only references their downstream {@code Subscriber} thus the chain can get GC'd
+   * when the reference to the final {@code Subscriber} is dropped).
+   * </ul>
+   */
+  void required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 3) and requests {@code Long.MAX_VALUE} from it, verifying that the
+   * {@code Publisher} emits all of its items and completes normally
+   * and does not keep spinning attempting to fulfill the {@code Long.MAX_VALUE} demand by some means.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.17'>3.17</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void required_spec317_mustSupportAPendingElementCountUpToLongMaxValue() throws Throwable;
+  /**
+   * Asks for a short {@code Publisher} (length 3) and requests {@code Long.MAX_VALUE} from it in total (split across
+   * two {@code Long.MAX_VALUE / 2} and one {@code request(1)}), verifying that the
+   * {@code Publisher} emits all of its items and completes normally.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.17'>3.17</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than 3.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} implements adding individual request amounts together properly (not overflowing into zero or negative pending request amounts)
+   * or not properly deducing the number of emitted items from the pending amount,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void required_spec317_mustSupportACumulativePendingElementCountUpToLongMaxValue() throws Throwable;
+  /**
+   * Asks for a very long {@code Publisher} (up to {@code Integer.MAX_VALUE}), requests {@code Long.MAX_VALUE - 1} after
+   * each received item and expects no failure due to a potential overflow in the pending emission count while consuming
+   * 10 items and cancelling the sequence.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.17'>3.17</a>
+   * <p>
+   * The test is not executed if {@link org.reactivestreams.tck.PublisherVerification#maxElementsFromPublisher()} is less than {@code Integer.MAX_VALUE}.
+   * <p>
+   * The request pattern is one {@code request(1)} upfront and ten {@code request(Long.MAX_VALUE - 1)} after.
+   * <p>
+   * If this test fails, the following could be checked within the {@code Publisher} implementation:
+   * <ul>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Publisher} has some time-delay behavior,</li>
+   * <li>make sure the {@link #required_createPublisher1MustProduceAStreamOfExactly1Element()} and {@link #required_createPublisher3MustProduceAStreamOfExactly3Elements()} tests pass,</li>
+   * <li>if the {@code Publisher} implementation considers the cumulative request amount it receives,</li>
+   * <li>if the {@code Publisher} implements adding individual request amounts together properly (not overflowing into zero or negative pending request amounts)
+   * or not properly deducing the number of emitted items from the pending amount,</li>
+   * <li>if the {@code Publisher} doesn't lose any {@code request()} signal and the state transition from idle -&gt; emitting or emitting -&gt; keep emitting works properly.</li>
+   * </ul>
+   */
+  void required_spec317_mustNotSignalOnErrorWhenPendingAboveLongMaxValue() throws Throwable;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/SubscriberBlackboxVerificationRules.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+import org.reactivestreams.tck.SubscriberBlackboxVerification;
+
+/**
+ * Internal TCK use only.
+ * Add / Remove tests for SubscriberBlackboxVerification here to make sure that they arre added/removed in the other places.
+ */
+public interface SubscriberBlackboxVerificationRules {
+  /**
+   * Asks for a {@code Subscriber} instance, expects it to call {@code request()} in
+   * a timely manner and signals as many {@code onNext} items as the very first request
+   * amount specified by the {@code Subscriber}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.1'>2.1</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>This test emits the number of items requested thus the {@code Subscriber} implementation
+   * should not request too much.</li>
+   * <li>Only the very first {@code request} amount is considered.</li>
+   * <li>This test doesn't signal {@code onComplete} after the first set of {@code onNext} signals
+   * has been emitted and may cause resource leak in
+   * {@code Subscriber}s that expect a finite {@code Publisher}.</li>
+   * <li>The test ignores cancellation from the {@code Subscriber} and emits the requested amount regardless.</li>
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} requires external stimulus to begin requesting; override the
+   * {@link SubscriberBlackboxVerification#triggerRequest(org.reactivestreams.Subscriber)} method
+   *  in this case,</li>
+   * <li>the {@code TestEnvironment} has large enough timeout specified in case the {@code Subscriber} has some time-delay behavior,</li>
+   * <li>if the {@code Subscriber} requests zero or a negative value in some circumstances,</li>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onNext} methods.
+   * </ul>
+   */
+  void required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() throws Throwable;
+  /**
+   * Currently, this test is skipped because there is no agreed upon approach how
+   * to detect if the {@code Subscriber} really goes async or just responds in
+   * a timely manner.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.2'>2.2</a>
+   */
+  void untested_spec202_blackbox_shouldAsynchronouslyDispatch() throws Exception;
+  /**
+   * Asks for a {@code Subscriber}, signals an {@code onSubscribe} followed by an {@code onComplete} synchronously,
+   * and checks if neither {@code request} nor {@code cancel} was called from within the {@code Subscriber}'s
+   * {@code onComplete} implementation.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.3'>2.3</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The test checks for the presensce of method named "onComplete" in the current stacktrace when handling
+   * the {@code request} or {@code cancel} calls in the test's own {@code Subscription}.
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>no calls happen to {@code request} or {@code cancel} in response to an {@code onComplete}
+   * directly or indirectly,</li>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onComplete} methods.
+   * </ul>
+   */
+  void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable;
+  /**
+   * Asks for a {@code Subscriber}, signals an {@code onSubscribe} followed by an {@code onError} synchronously,
+   * and checks if neither {@code request} nor {@code cancel} was called from within the {@code Subscriber}'s
+   * {@code onComplete} implementation.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.3'>2.3</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The test checks for the presensce of method named "onError" in the current stacktrace when handling
+   * the {@code request} or {@code cancel} calls in the test's own {@code Subscription}.
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>no calls happen to {@code request} or {@code cancel} in response to an {@code onError}
+   * directly or indirectly,</li>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onError} methods.
+   * </ul>
+   */
+  void required_spec203_blackbox_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable;
+  /**
+   * Currently, this test is skipped because there is no way to check what the {@code Subscriber} "considers"
+   * since rule §2.3 forbids interaction from within the {@code onError} and {@code onComplete} methods.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.4'>2.4</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>It would be possible to check if there was an async interaction with the test's {@code Subscription}
+   * within a grace period but such check is still not generally decisive.</li>
+   * </ul>
+   */
+  void untested_spec204_blackbox_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception;
+  /**
+   * Asks for a {@code Subscriber}, signals {@code onSubscribe} twice synchronously and expects the second {@code Subscription} gets
+   * cancelled in a timely manner and without any calls to its {@code request} method.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.5'>2.5</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The test doesn't signal any other events than {@code onSubscribe} and may cause resource leak in
+   * {@code Subscriber}s that expect a finite {@code Publisher}.
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscribe.onSubscribe} implementation actually tries to detect multiple calls to it,</li>
+   * <li>if the second {@code Subscription} is cancelled asynchronously and that takes longer time than
+   * the {@code TestEnvironment}'s timeout permits.</li>
+   * </ul>
+   */
+  void required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Exception;
+
+  /**
+   * Currently, this test is skipped because it requires more control over the {@code Subscriber} implementation
+   * to make it cancel the {@code Subscription} for some external condition.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.6'>2.6</a>
+   */
+  void untested_spec206_blackbox_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception;
+  /**
+   * Currently, this test is skipped because it requires more control over the {@code Subscriber} implementation
+   * to issue requests based on external stimulus.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.7'>2.7</a>
+   */
+  void untested_spec207_blackbox_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception;
+  /**
+   * Currently, this test is skipped because there is no way to make the {@code Subscriber} implementation
+   * cancel the test's {@code Subscription} and check the outcome of sending {@code onNext}s after such
+   * cancel.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.8'>2.8</a>
+   */
+  void untested_spec208_blackbox_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable;
+  /**
+   * Asks for a {@code Subscriber}, expects it to request some amount and in turn be able to receive an {@code onComplete}
+   * synchronously from the {@code request} call without any {@code onNext} signals before that.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.9'>2.9</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The test ignores cancellation from the {@code Subscriber}.</li>
+   * <li>Invalid request amounts are ignored by this test.</li>
+   * <li>Concurrent calls to the test's {@code Subscription.request()} must be externally synchronized, otherwise
+   * such case results probabilistically in multiple {@code onComplete} calls by the test.</li>
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onComplete} methods.
+   * <li>if the {@code Subscriber} requires external stimulus to begin requesting; override the
+   * {@link SubscriberBlackboxVerification#triggerRequest(org.reactivestreams.Subscriber)} method
+   *  in this case,</li>
+   * </ul>
+   */
+  void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable;
+  /**
+   * Asks for a {@code Subscriber} and expects it to handle {@code onComplete} independent of whether the {@code Subscriber}
+   * requests items or not.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.9'>2.9</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>Currently, the test doesn't call {@code onSubscribe} on the {@code Subscriber} which violates §1.9.
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onComplete} methods.
+   * </ul>
+   */
+  void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable;
+  /**
+   * Asks for a {@code Subscriber}, signals {@code onSubscribe} followed by an {@code onError} synchronously.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.10'>2.10</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>Despite the method name, the test doesn't expect a request signal from {@code Subscriber} and emits the
+   * {@code onError} signal anyway.
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onError} methods.
+   * </ul>
+   */
+  void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable;
+
+  /**
+   * Asks for a {@code Subscriber}, signals {@code onSubscribe} followed by an {@code onError} synchronously.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.10'>2.10</a>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws an unchecked exception from its {@code onSubscribe} or
+   * {@code onError} methods.
+   * </ul>
+   */
+  void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable;
+
+  /**
+   * Currently, this test is skipped because it would require analyzing what the {@code Subscriber} implementation
+   * does.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.11'>2.11</a>
+   */
+  void untested_spec211_blackbox_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception;
+  /**
+   * Currently, this test is skipped because the test for
+   * {@link #required_spec205_blackbox_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal §2.5}
+   * is in a better position to test for handling the reuse of the same {@code Subscriber}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.12'>2.12</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>In addition to §2.5, this rule could be better verified when testing a {@code Publisher}'s subscription behavior.
+   * </ul>
+   */
+  void untested_spec212_blackbox_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality() throws Throwable;
+  /**
+   * Currently, this test is skipped because it would require more control over the {@code Subscriber} to
+   * fail internally in response to a set of legal event emissions, not throw any exception from the {@code Subscriber}
+   * methods and have it cancel the {@code Subscription}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.13'>2.13</a>
+   */
+  void untested_spec213_blackbox_failingOnSignalInvocation() throws Exception;
+  /**
+   * Asks for a {@code Subscriber} and signals an {@code onSubscribe} event with {@code null} as a parameter and
+   * expects an immediate {@code NullPointerException} to be thrown by the {@code Subscriber.onSubscribe} method.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.13'>2.13</a>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws a {@code NullPointerException} from its {@code onSubscribe} method
+   * in response to a {@code null} parameter and not some other unchecked exception or no exception at all.
+   * </ul>
+   */
+  void required_spec213_blackbox_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+  /**
+   * Asks for a {@code Subscriber}, signals an {@code onSubscribe} event followed by a
+   * {@code onNext} with {@code null} as a parameter and
+   * expects an immediate {@code NullPointerException} to be thrown by the {@code Subscriber.onNext} method.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.13'>2.13</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The test ignores cancellation and requests from the {@code Subscriber} and emits the {@code onNext}
+   * signal with a {@code null} parameter anyway.</li>
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws a {@code NullPointerException} from its {@code onNext} method
+   * in response to a {@code null} parameter and not some other unchecked exception or no exception at all.
+   * </ul>
+   */
+  void required_spec213_blackbox_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+  /**
+   * Asks for a {@code Subscriber}, signals an {@code onSubscribe} event followed by a
+   * {@code onError} with {@code null} as a parameter and
+   * expects an immediate {@code NullPointerException} to be thrown by the {@code Subscriber.onError} method.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#2.13'>2.13</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The test ignores cancellation from the {@code Subscriber} and emits the {@code onError}
+   * signal with a {@code null} parameter anyway.</li>
+   * </ul>
+   * <p>
+   * If this test fails, the following could be checked within the {@code Subscriber} implementation:
+   * <ul>
+   * <li>if the {@code Subscriber} throws a {@code NullPointerException} from its {@code onNext} method
+   * in response to a {@code null} parameter and not some other unchecked exception or no exception at all.
+   * </ul>
+   */
+  void required_spec213_blackbox_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+  /**
+   * Currently, this test is skipped because there is no agreed upon way for specifying, enforcing and testing
+   * a {@code Subscriber} with an arbitrary context.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.1'>3.1</a>
+   */
+  void untested_spec301_blackbox_mustNotBeCalledOutsideSubscriberContext() throws Exception;
+  /**
+   * Currently, this test is skipped because element production is the responsibility of the {@code Publisher} and
+   * a {@code Subscription} is not expected to be the active element in an established subscription.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.8'>3.8</a>
+   */
+  void untested_spec308_blackbox_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable;
+  /**
+   * Currently, this test is skipped because element production is the responsibility of the {@code Publisher} and
+   * a {@code Subscription} is not expected to be the active element in an established subscription.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.10'>3.10</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>This could be tested with a synchronous source currently not available within the TCK.</li>
+   * </ul>
+   */
+  void untested_spec310_blackbox_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception;
+  /**
+   * Currently, this test is skipped because signal production is the responsibility of the {@code Publisher} and
+   * a {@code Subscription} is not expected to be the active element in an established subscription.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.11'>3.11</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>Tests {@link #required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() §2.9}
+   * and {@link #required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() §2.10} are
+   * supposed to cover this case from the {@code Subscriber's} perspective.</li>
+   * </ul>
+   */
+  void untested_spec311_blackbox_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception;
+  /**
+   * Currently, this test is skipped because it is the responsibility of the {@code Publisher} deal with the case
+   * that all subscribers have cancelled their subscription.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.14'>3.14</a>
+   * <p>
+   * Notes:
+   * <ul>
+   * <li>The specification lists this as an optional behavior because only some {@code Publisher} implementations
+   * (most likely {@code Processor}s) would coordinate with multiple {@code Subscriber}s.</li>
+   * </ul>
+   */
+  void untested_spec314_blackbox_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception;
+  /**
+   * Currently, this test is skipped because it requires more control over the {@code Subscriber} implementation
+   * thus there is no way to detect that the {@code Subscriber} called its own {@code onError} method in response
+   * to an exception thrown from {@code Subscription.cancel}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.15'>3.15</a>
+   */
+  void untested_spec315_blackbox_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception;
+  /**
+   * Currently, this test is skipped because it requires more control over the {@code Subscriber} implementation
+   * thus there is no way to detect that the {@code Subscriber} called its own {@code onError} method in response
+   * to an exception thrown from {@code Subscription.request}.
+   * <p>
+   * <b>Verifies rule:</b> <a href='https://github.com/reactive-streams/reactive-streams-jvm#3.16'>3.16</a>
+   */
+  void untested_spec316_blackbox_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/SubscriberBufferOverflowException.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+public final class SubscriberBufferOverflowException extends RuntimeException {
+  public SubscriberBufferOverflowException() {
+  }
+
+  public SubscriberBufferOverflowException(String message) {
+    super(message);
+  }
+
+  public SubscriberBufferOverflowException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public SubscriberBufferOverflowException(Throwable cause) {
+    super(cause);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/SubscriberWhiteboxVerificationRules.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+/**
+ * Internal TCK use only.
+ * Add / Remove tests for PublisherVerificaSubscriberWhiteboxVerification here to make sure that they arre added/removed in the other places.
+ */
+public interface SubscriberWhiteboxVerificationRules {
+  void required_exerciseWhiteboxHappyPath() throws Throwable;
+  void required_spec201_mustSignalDemandViaSubscriptionRequest() throws Throwable;
+  void untested_spec202_shouldAsynchronouslyDispatch() throws Exception;
+  void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnComplete() throws Throwable;
+  void required_spec203_mustNotCallMethodsOnSubscriptionOrPublisherInOnError() throws Throwable;
+  void untested_spec204_mustConsiderTheSubscriptionAsCancelledInAfterRecievingOnCompleteOrOnError() throws Exception;
+  void required_spec205_mustCallSubscriptionCancelIfItAlreadyHasAnSubscriptionAndReceivesAnotherOnSubscribeSignal() throws Throwable;
+  void untested_spec206_mustCallSubscriptionCancelIfItIsNoLongerValid() throws Exception;
+  void untested_spec207_mustEnsureAllCallsOnItsSubscriptionTakePlaceFromTheSameThreadOrTakeCareOfSynchronization() throws Exception;
+  void required_spec208_mustBePreparedToReceiveOnNextSignalsAfterHavingCalledSubscriptionCancel() throws Throwable;
+  void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() throws Throwable;
+  void required_spec209_mustBePreparedToReceiveAnOnCompleteSignalWithoutPrecedingRequestCall() throws Throwable;
+  void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() throws Throwable;
+  void required_spec210_mustBePreparedToReceiveAnOnErrorSignalWithoutPrecedingRequestCall() throws Throwable;
+  void untested_spec211_mustMakeSureThatAllCallsOnItsMethodsHappenBeforeTheProcessingOfTheRespectiveEvents() throws Exception;
+  void untested_spec212_mustNotCallOnSubscribeMoreThanOnceBasedOnObjectEquality_specViolation() throws Throwable;
+  void untested_spec213_failingOnSignalInvocation() throws Exception;
+  void required_spec213_onSubscribe_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+  void required_spec213_onNext_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+  void required_spec213_onError_mustThrowNullPointerExceptionWhenParametersAreNull() throws Throwable;
+  void untested_spec301_mustNotBeCalledOutsideSubscriberContext() throws Exception;
+  void required_spec308_requestMustRegisterGivenNumberElementsToBeProduced() throws Throwable;
+  void untested_spec310_requestMaySynchronouslyCallOnNextOnSubscriber() throws Exception;
+  void untested_spec311_requestMaySynchronouslyCallOnCompleteOrOnError() throws Exception;
+  void untested_spec314_cancelMayCauseThePublisherToShutdownIfNoOtherSubscriptionExists() throws Exception;
+  void untested_spec315_cancelMustNotThrowExceptionAndMustSignalOnError() throws Exception;
+  void untested_spec316_requestMustNotThrowExceptionAndMustOnErrorTheSubscriber() throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/reactivestreams-tck/org/reactivestreams/tck/flow/support/TestException.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.reactivestreams.tck.flow.support;
+
+/**
+ * Exception used by the TCK to signal failures.
+ * May be thrown or signalled through {@link org.reactivestreams.Subscriber#onError(Throwable)}.
+ */
+public final class TestException extends RuntimeException {
+  public TestException() {
+    super("Test Exception: Boom!");
+  }
+}
--- a/test/jdk/java/nio/channels/FileChannel/MapTest.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/jdk/java/nio/channels/FileChannel/MapTest.java	Tue Jul 02 12:03:49 2019 -0400
@@ -24,7 +24,7 @@
 /* @test
  * @bug 4429043 8002180
  * @summary Test file mapping with FileChannel
- * @run main/othervm MapTest
+ * @run main/othervm/timeout=240 MapTest
  * @key randomness
  */
 
@@ -195,7 +195,7 @@
      * the data exercising various valid and invalid writeback ranges.
      */
     private static void testForce() throws Exception {
-        for (int x=0; x<100; x++) {
+        for (int x=0; x<50; x++) {
             try (RandomAccessFile raf = new RandomAccessFile(blah, "rw")) {
                 FileChannel fc = raf.getChannel();
                 final int BLOCK_SIZE = 64;
--- a/test/jdk/java/util/Locale/LocaleProvidersRun.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/jdk/java/util/Locale/LocaleProvidersRun.java	Tue Jul 02 12:03:49 2019 -0400
@@ -159,7 +159,9 @@
     private static void testRun(String prefList, String methodName,
             String param1, String param2, String param3) throws Throwable{
         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("java");
-        launcher.addToolArg("-cp")
+        launcher.addToolArg("-ea")
+                .addToolArg("-esa")
+                .addToolArg("-cp")
                 .addToolArg(Utils.TEST_CLASS_PATH)
                 .addToolArg("-Djava.locale.providers=" + prefList)
                 .addToolArg("--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED")
--- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java	Tue Jul 02 12:03:49 2019 -0400
@@ -131,10 +131,7 @@
      * Create an instance of SSLContext for client use.
      */
     protected SSLContext createClientSSLContext() throws Exception {
-        return createSSLContext(trustedCertStrs,
-                endEntityCertStrs, endEntityPrivateKeys,
-                endEntityPrivateKeyAlgs,
-                endEntityPrivateKeyNames,
+        return createSSLContext(TRUSTED_CERTS, END_ENTITY_CERTS,
                 getClientContextParameters());
     }
 
@@ -142,10 +139,7 @@
      * Create an instance of SSLContext for server use.
      */
     protected SSLContext createServerSSLContext() throws Exception {
-        return createSSLContext(trustedCertStrs,
-                endEntityCertStrs, endEntityPrivateKeys,
-                endEntityPrivateKeyAlgs,
-                endEntityPrivateKeyNames,
+        return createSSLContext(TRUSTED_CERTS, END_ENTITY_CERTS,
                 getServerContextParameters());
     }
 
@@ -362,330 +356,24 @@
      * Certificates and keys used in the test.
      */
     // Trusted certificates.
-    private final static String[] trustedCertStrs = {
-        // SHA256withECDSA, curve prime256v1
-        // Validity
-        //     Not Before: May 22 07:18:16 2018 GMT
-        //     Not After : May 17 07:18:16 2038 GMT
-        // Subject Key Identifier:
-        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
-        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
-        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" +
-        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
-        "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" +
-        "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" +
-        "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" +
-        "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" +
-        "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" +
-        "2YEHlSQUAbwwqCDEVB5KxaqP\n" +
-        "-----END CERTIFICATE-----",
-        // -----BEGIN PRIVATE KEY-----
-        // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd
-        // XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd
-        // LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp
-        // -----END PRIVATE KEY-----
-
-        // SHA256withRSA, 2048 bits
-        // Validity
-        //     Not Before: May 22 07:18:16 2018 GMT
-        //     Not After : May 17 07:18:16 2038 GMT
-        // Subject Key Identifier:
-        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
-        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
-        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" +
-        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
-        "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" +
-        "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" +
-        "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" +
-        "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" +
-        "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" +
-        "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" +
-        "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" +
-        "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" +
-        "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" +
-        "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" +
-        "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" +
-        "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" +
-        "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" +
-        "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" +
-        "-----END CERTIFICATE-----",
-        // -----BEGIN PRIVATE KEY-----
-        // MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD
-        // Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB
-        // emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE
-        // +X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq
-        // 7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B
-        // qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4
-        // GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9
-        // rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF
-        // JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2
-        // kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/
-        // 25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/
-        // +5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO
-        // a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS
-        // zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h
-        // De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ
-        // HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W
-        // 9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2
-        // +MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF
-        // 2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg
-        // iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S
-        // Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx
-        // HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C
-        // kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh
-        // 63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K
-        // z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH
-        // zoXBInYwRG9KE/Bw5elhUw==
-        // -----END PRIVATE KEY-----
-
-        // SHA256withDSA, 2048 bits
-        // Validity
-        //     Not Before: May 22 07:18:18 2018 GMT
-        //     Not After : May 17 07:18:18 2038 GMT
-        // Subject Key Identifier:
-        //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
-        "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
-        "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" +
-        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" +
-        "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" +
-        "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" +
-        "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" +
-        "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" +
-        "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" +
-        "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" +
-        "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" +
-        "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" +
-        "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" +
-        "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" +
-        "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" +
-        "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" +
-        "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" +
-        "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" +
-        "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" +
-        "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" +
-        "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" +
-        "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" +
-        "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" +
-        "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" +
-        "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" +
-        "J+g=\n" +
-        "-----END CERTIFICATE-----"
-        // -----BEGIN PRIVATE KEY-----
-        // MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O
-        // Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt
-        // l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk
-        // p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW
-        // Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f
-        // qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA
-        // tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe
-        // 5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY
-        // sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X
-        // xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0
-        // eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU
-        // tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ
-        // xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4=
-        // -----END PRIVATE KEY-----
-        };
+    protected final static Cert[] TRUSTED_CERTS = {
+            Cert.CA_ECDSA_SECP256R1,
+            Cert.CA_RSA_2048,
+            Cert.CA_DSA_2048 };
 
     // End entity certificate.
-    private final static String[] endEntityCertStrs = {
-        // SHA256withECDSA, curve prime256v1
-        // Validity
-        //     Not Before: May 22 07:18:16 2018 GMT
-        //     Not After : May 17 07:18:16 2038 GMT
-        // Authority Key Identifier:
-        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
-        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
-        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" +
-        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" +
-        "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" +
-        "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" +
-        "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" +
-        "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" +
-        "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" +
-        "-----END CERTIFICATE-----",
-
-        // SHA256withRSA, 2048 bits
-        // Validity
-        //     Not Before: May 22 07:18:16 2018 GMT
-        //     Not After : May 17 07:18:16 2038 GMT
-        // Authority Key Identifier:
-        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
-        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
-        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
-        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
-        "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +
-        "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" +
-        "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" +
-        "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" +
-        "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" +
-        "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" +
-        "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" +
-        "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" +
-        "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" +
-        "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" +
-        "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" +
-        "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" +
-        "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" +
-        "e57NnbT7KM+Grw==\n" +
-        "-----END CERTIFICATE-----",
-
-        // SHA256withRSA, curv prime256v1
-        // Validity
-        //     Not Before: May 22 07:18:16 2018 GMT
-        //     Not After : May 21 07:18:16 2028 GMT
-        // Authority Key Identifier:
-        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
-        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
-        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
-        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
-        "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" +
-        "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" +
-        "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" +
-        "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" +
-        "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" +
-        "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" +
-        "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" +
-        "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" +
-        "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" +
-        "-----END CERTIFICATE-----",
-
-        // SHA256withDSA, 2048 bits
-        // Validity
-        //     Not Before: May 22 07:18:20 2018 GMT
-        //     Not After : May 17 07:18:20 2038 GMT
-        // Authority Key Identifier:
-        //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
-        "-----BEGIN CERTIFICATE-----\n" +
-        "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
-        "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
-        "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" +
-        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
-        "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" +
-        "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" +
-        "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" +
-        "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" +
-        "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" +
-        "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" +
-        "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" +
-        "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" +
-        "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" +
-        "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" +
-        "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" +
-        "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" +
-        "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" +
-        "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" +
-        "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" +
-        "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" +
-        "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" +
-        "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" +
-        "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" +
-        "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" +
-        "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" +
-        "-----END CERTIFICATE-----"
-        };
-
-    // Private key in the format of PKCS#8.
-    private final static String[] endEntityPrivateKeys = {
-        //
-        // EC private key related to cert endEntityCertStrs[0].
-        //
-        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" +
-        "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" +
-        "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6",
-
-        //
-        // RSA private key related to cert endEntityCertStrs[1].
-        //
-        "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" +
-        "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" +
-        "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" +
-        "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" +
-        "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" +
-        "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" +
-        "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" +
-        "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" +
-        "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" +
-        "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" +
-        "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" +
-        "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" +
-        "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" +
-        "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" +
-        "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" +
-        "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" +
-        "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" +
-        "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" +
-        "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" +
-        "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" +
-        "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" +
-        "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" +
-        "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" +
-        "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" +
-        "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" +
-        "qAL3go42DYeYhu/WnECMeis=",
-
-        //
-        // EC private key related to cert endEntityCertStrs[2].
-        //
-        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" +
-        "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" +
-        "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT",
-
-        //
-        // DSA private key related to cert endEntityCertStrs[3].
-        //
-        "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" +
-        "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" +
-        "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" +
-        "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" +
-        "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" +
-        "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" +
-        "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" +
-        "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" +
-        "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" +
-        "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" +
-        "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" +
-        "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" +
-        "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw="
-        };
-
-    // Private key algorithm of endEntityPrivateKeys.
-    private final static String[] endEntityPrivateKeyAlgs = {
-        "EC",
-        "RSA",
-        "EC",
-        "DSA",
-        };
-
-    // Private key names of endEntityPrivateKeys.
-    private final static String[] endEntityPrivateKeyNames = {
-        "ecdsa",
-        "rsa",
-        "ec-rsa",
-        "dsa",
-        };
+    protected final static Cert[] END_ENTITY_CERTS = {
+            Cert.EE_ECDSA_SECP256R1,
+            Cert.EE_RSA_2048,
+            Cert.EE_EC_RSA_SECP256R1,
+            Cert.EE_DSA_2048 };
 
     /*
      * Create an instance of SSLContext with the specified trust/key materials.
      */
-    private SSLContext createSSLContext(
-            String[] trustedMaterials,
-            String[] keyMaterialCerts,
-            String[] keyMaterialKeys,
-            String[] keyMaterialKeyAlgs,
-            String[] keyMaterialKeyNames,
+    public static SSLContext createSSLContext(
+            Cert[] trustedCerts,
+            Cert[] endEntityCerts,
             ContextParameters params) throws Exception {
 
         KeyStore ts = null;     // trust store
@@ -697,51 +385,41 @@
 
         // Import the trused certs.
         ByteArrayInputStream is;
-        if (trustedMaterials != null && trustedMaterials.length != 0) {
+        if (trustedCerts != null && trustedCerts.length != 0) {
             ts = KeyStore.getInstance("JKS");
             ts.load(null, null);
 
-            Certificate[] trustedCert =
-                    new Certificate[trustedMaterials.length];
-            for (int i = 0; i < trustedMaterials.length; i++) {
-                String trustedCertStr = trustedMaterials[i];
-
-                is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            Certificate[] trustedCert = new Certificate[trustedCerts.length];
+            for (int i = 0; i < trustedCerts.length; i++) {
+                is = new ByteArrayInputStream(trustedCerts[i].certStr.getBytes());
                 try {
                     trustedCert[i] = cf.generateCertificate(is);
                 } finally {
                     is.close();
                 }
 
-                ts.setCertificateEntry("trusted-cert-" + i, trustedCert[i]);
+                ts.setCertificateEntry(
+                        "trusted-cert-" + trustedCerts[i].name(), trustedCert[i]);
             }
         }
 
         // Import the key materials.
-        //
-        // Note that certification pathes bigger than one are not supported yet.
-        boolean hasKeyMaterials =
-            (keyMaterialCerts != null) && (keyMaterialCerts.length != 0) &&
-            (keyMaterialKeys != null) && (keyMaterialKeys.length != 0) &&
-            (keyMaterialKeyAlgs != null) && (keyMaterialKeyAlgs.length != 0) &&
-            (keyMaterialCerts.length == keyMaterialKeys.length) &&
-            (keyMaterialCerts.length == keyMaterialKeyAlgs.length);
-        if (hasKeyMaterials) {
+        if (endEntityCerts != null && endEntityCerts.length != 0) {
             ks = KeyStore.getInstance("JKS");
             ks.load(null, null);
 
-            for (int i = 0; i < keyMaterialCerts.length; i++) {
-                String keyCertStr = keyMaterialCerts[i];
-
+            for (int i = 0; i < endEntityCerts.length; i++) {
                 // generate the private key.
                 PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
-                    Base64.getMimeDecoder().decode(keyMaterialKeys[i]));
+                    Base64.getMimeDecoder().decode(endEntityCerts[i].privKeyStr));
                 KeyFactory kf =
-                    KeyFactory.getInstance(keyMaterialKeyAlgs[i]);
+                    KeyFactory.getInstance(
+                            endEntityCerts[i].keyAlgo);
                 PrivateKey priKey = kf.generatePrivate(priKeySpec);
 
                 // generate certificate chain
-                is = new ByteArrayInputStream(keyCertStr.getBytes());
+                is = new ByteArrayInputStream(
+                        endEntityCerts[i].certStr.getBytes());
                 Certificate keyCert = null;
                 try {
                     keyCert = cf.generateCertificate(is);
@@ -752,7 +430,7 @@
                 Certificate[] chain = new Certificate[] { keyCert };
 
                 // import the key entry.
-                ks.setKeyEntry("cert-" + keyMaterialKeyNames[i],
+                ks.setKeyEntry("cert-" + endEntityCerts[i].name(),
                         priKey, passphrase, chain);
             }
         }
@@ -763,7 +441,7 @@
         tmf.init(ts);
 
         SSLContext context = SSLContext.getInstance(params.contextProtocol);
-        if (hasKeyMaterials && ks != null) {
+        if (endEntityCerts != null && endEntityCerts.length != 0 && ks != null) {
             KeyManagerFactory kmf =
                     KeyManagerFactory.getInstance(params.kmAlgorithm);
             kmf.init(ks, passphrase);
@@ -928,4 +606,413 @@
         System.out.println(prefix + ": " + cause);
         cause.printStackTrace(System.out);
     }
+
+    public static enum Cert {
+
+        CA_ECDSA_SECP256R1(
+                "EC",
+                // SHA256withECDSA, curve secp256r1
+                // Validity
+                //     Not Before: May 22 07:18:16 2018 GMT
+                //     Not After : May 17 07:18:16 2038 GMT
+                // Subject Key Identifier:
+                //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+                "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+                "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" +
+                "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
+                "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" +
+                "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" +
+                "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" +
+                "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" +
+                "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" +
+                "2YEHlSQUAbwwqCDEVB5KxaqP\n" +
+                "-----END CERTIFICATE-----",
+                "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd\n" +
+                "XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd\n" +
+                "LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp"),
+
+        CA_ECDSA_SECP384R1(
+                "EC",
+                // SHA384withECDSA, curve secp384r1
+                // Validity
+                //     Not Before: Jun 24 08:15:06 2019 GMT
+                //     Not After : Jun 19 08:15:06 2039 GMT
+                // Subject Key Identifier:
+                //     0a:93:a9:a0:bf:e7:d5:48:9d:4f:89:15:c6:51:98:80:05:51:4e:4e
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIICCDCCAY6gAwIBAgIUCpOpoL/n1UidT4kVxlGYgAVRTk4wCgYIKoZIzj0EAwMw\n" +
+                "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" +
+                "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" +
+                "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" +
+                "dCBTZXJpdmNlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENVQN1wXWFdgC6u/dDdiC\n" +
+                "y+WtMTF66oL/0BSm+1ZqsogamzCryawOcHgiuXgWzx5CQ3LuOC+tDFyXpGfHuCvb\n" +
+                "dkzxPrP5n9NrR8/uRPe5l1KOUbchviU8z9cTP+LZxnZDo1MwUTAdBgNVHQ4EFgQU\n" +
+                "SktSFArR1p/5mXV0kyo0RxIVa/UwHwYDVR0jBBgwFoAUSktSFArR1p/5mXV0kyo0\n" +
+                "RxIVa/UwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjBZvoNmq3/v\n" +
+                "RD2gBTyvxjS9h0rsMRLHDnvul/KWngytwGPTOBo0Y8ixQXSjdKoc3rkCMQDkiNgx\n" +
+                "IDxuHedmrLQKIPnVcthTmwv7//jHiqGoKofwChMo2a1P+DQdhszmeHD/ARQ=\n" +
+                "-----END CERTIFICATE-----",
+                "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDChlbt0NF8oIKODSxn2\n" +
+                "WXCXuJm3z78LRkzYQS3Nx5NMjei5ytkFZz4qvD4XXMWlTEyhZANiAAQ1VA3XBdYV\n" +
+                "2ALq790N2ILL5a0xMXrqgv/QFKb7VmqyiBqbMKvJrA5weCK5eBbPHkJDcu44L60M\n" +
+                "XJekZ8e4K9t2TPE+s/mf02tHz+5E97mXUo5RtyG+JTzP1xM/4tnGdkM="),
+
+        CA_ECDSA_SECP521R1(
+                "EC",
+                // SHA512withECDSA, curve secp521r1
+                // Validity
+                //     Not Before: Jun 24 08:15:06 2019 GMT
+                //     Not After : Jun 19 08:15:06 2039 GMT
+                // Subject Key Identifier:
+                //     25:ca:68:76:6d:29:17:9b:71:78:45:2d:d4:c6:e4:5d:fe:25:ff:90
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIICUzCCAbSgAwIBAgIUJcpodm0pF5txeEUt1MbkXf4l/5AwCgYIKoZIzj0EAwQw\n" +
+                "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" +
+                "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" +
+                "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" +
+                "dCBTZXJpdmNlMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAmFD5VmB2MdyJ6k+E\n" +
+                "eP4JncrE65ySL07gVmFwnr8otOt3NtRAyzmviMNNXXjo5R5NqNjKP4pr92JjT0sO\n" +
+                "D65yngkBtH151Ev/fiKPLxkXL9GzfKdWHVhDX7Zg6DUydzukzZV2/dIyloAIqwlz\n" +
+                "QVKJqT7RypDufdng8hnE9YfKo6ypZiujUzBRMB0GA1UdDgQWBBRAIrxa7WqtqUCe\n" +
+                "HFuKREDC92spvTAfBgNVHSMEGDAWgBRAIrxa7WqtqUCeHFuKREDC92spvTAPBgNV\n" +
+                "HRMBAf8EBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAe22iirZnODCmlpxcv57\n" +
+                "3g5BEE60C+dtYmTqR4DtFyDaTRQ5CFf4ZxvQPIbD+SXi5Cbrl6qtrZG0cjUihPkC\n" +
+                "Hi1hAkIAiEcO7nMPgQLny+GrciojfN+bZXME/dPz6KHBm/89f8Me+jawVnv6y+df\n" +
+                "2Sbafh1KV6ntWQtB4bK3MXV8Ym9Eg1I=\n" +
+                "-----END CERTIFICATE-----",
+                "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAV8dZszV6+nLw3LeA\n" +
+                "Q+qLJLGaqyjlsQkaopCPcmoRdy1HX6AzB/YnKsPkHp/9DQN6A2JgUhFG5B0XvKSk\n" +
+                "BqNNuSGhgYkDgYYABACYUPlWYHYx3InqT4R4/gmdysTrnJIvTuBWYXCevyi063c2\n" +
+                "1EDLOa+Iw01deOjlHk2o2Mo/imv3YmNPSw4PrnKeCQG0fXnUS/9+Io8vGRcv0bN8\n" +
+                "p1YdWENftmDoNTJ3O6TNlXb90jKWgAirCXNBUompPtHKkO592eDyGcT1h8qjrKlm\n" +
+                "Kw=="),
+
+        CA_RSA_2048(
+                "RSA",
+                // SHA256withRSA, 2048 bits
+                // Validity
+                //     Not Before: May 22 07:18:16 2018 GMT
+                //     Not After : May 17 07:18:16 2038 GMT
+                // Subject Key Identifier:
+                //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+                "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+                "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" +
+                "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+                "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" +
+                "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" +
+                "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" +
+                "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" +
+                "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" +
+                "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" +
+                "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" +
+                "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" +
+                "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" +
+                "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" +
+                "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" +
+                "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" +
+                "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" +
+                "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" +
+                "-----END CERTIFICATE-----",
+                "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD\n" +
+                "Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB\n" +
+                "emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE\n" +
+                "+X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq\n" +
+                "7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B\n" +
+                "qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4\n" +
+                "GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9\n" +
+                "rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF\n" +
+                "JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2\n" +
+                "kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/\n" +
+                "25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/\n" +
+                "+5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO\n" +
+                "a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS\n" +
+                "zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h\n" +
+                "De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ\n" +
+                "HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W\n" +
+                "9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2\n" +
+                "+MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF\n" +
+                "2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg\n" +
+                "iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S\n" +
+                "Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx\n" +
+                "HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C\n" +
+                "kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh\n" +
+                "63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K\n" +
+                "z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH\n" +
+                "zoXBInYwRG9KE/Bw5elhUw=="),
+
+        CA_DSA_2048(
+                "DSA",
+                // SHA256withDSA, 2048 bits
+                // Validity
+                //     Not Before: May 22 07:18:18 2018 GMT
+                //     Not After : May 17 07:18:18 2038 GMT
+                // Subject Key Identifier:
+                //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+                "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+                "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" +
+                "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" +
+                "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" +
+                "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" +
+                "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" +
+                "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" +
+                "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" +
+                "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" +
+                "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" +
+                "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" +
+                "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" +
+                "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" +
+                "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" +
+                "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" +
+                "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" +
+                "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" +
+                "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" +
+                "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" +
+                "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" +
+                "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" +
+                "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" +
+                "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" +
+                "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" +
+                "J+g=\n" +
+                "-----END CERTIFICATE-----",
+                "MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O" +
+                "Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt" +
+                "l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk" +
+                "p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW" +
+                "Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f" +
+                "qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA" +
+                "tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe" +
+                "5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY" +
+                "sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X" +
+                "xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0" +
+                "eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU" +
+                "tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ" +
+                "xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4="),
+
+        EE_ECDSA_SECP256R1(
+                "EC",
+                // SHA256withECDSA, curve secp256r1
+                // Validity
+                //     Not Before: May 22 07:18:16 2018 GMT
+                //     Not After : May 17 07:18:16 2038 GMT
+                // Authority Key Identifier:
+                //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+                "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+                "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" +
+                "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" +
+                "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" +
+                "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" +
+                "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" +
+                "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" +
+                "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" +
+                "-----END CERTIFICATE-----",
+                "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" +
+                "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" +
+                "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6"),
+
+        EE_ECDSA_SECP384R1(
+                "EC",
+                // SHA384withECDSA, curve secp384r1
+                // Validity
+                //     Not Before: Jun 24 08:15:06 2019 GMT
+                //     Not After : Jun 19 08:15:06 2039 GMT
+                // Authority Key Identifier:
+                //     40:2D:AA:EE:66:AA:33:27:AD:9B:5D:52:9B:60:67:6A:2B:AD:52:D2
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIICEjCCAZegAwIBAgIUS3F0AqAXWRg07CnbknJzxofyBQMwCgYIKoZIzj0EAwMw\n" +
+                "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" +
+                "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" +
+                "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" +
+                "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwdjAQBgcqhkjOPQIB\n" +
+                "BgUrgQQAIgNiAARqElz8b6T07eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/w\n" +
+                "G8ASSevpgqgpi6EzpBZaaJxE3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEj\n" +
+                "iLjYmt3O0pwpklijQjBAMB0GA1UdDgQWBBRALaruZqozJ62bXVKbYGdqK61S0jAf\n" +
+                "BgNVHSMEGDAWgBRKS1IUCtHWn/mZdXSTKjRHEhVr9TAKBggqhkjOPQQDAwNpADBm\n" +
+                "AjEArVDFKf48xijN6huVUJzKCOP0zlWB5Js+DItIkZmLQuhciPLhLIB/rChf3Y4C\n" +
+                "xuP4AjEAmfLhQRI0O3pifpYzYSVh2G7/jHNG4eO+2dvgAcU+Lh2IIj/cpLaPFSvL\n" +
+                "J8FXY9Nj\n" +
+                "-----END CERTIFICATE-----",
+                "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDASuI9EtK29APXPipkc\n" +
+                "qDA+qwlewMjv/OcjUJ77kP1Vz62oVF9iY9SRIyFIUju8wt+hZANiAARqElz8b6T0\n" +
+                "7eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/wG8ASSevpgqgpi6EzpBZaaJxE\n" +
+                "3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEjiLjYmt3O0pwpklg="),
+
+        EE_ECDSA_SECP521R1(
+                "EC",
+                // SHA512withECDSA, curve secp521r1
+                // Validity
+                //     Not Before: Jun 24 08:15:06 2019 GMT
+                //     Not After : Jun 19 08:15:06 2039 GMT
+                // Authority Key Identifier:
+                //     7B:AA:79:A4:49:DD:59:34:F0:86:6C:51:C7:30:F4:CE:C5:81:8A:28
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIICXDCCAb2gAwIBAgIUck4QTsbHNqUfPxfGPJLYbedFPdswCgYIKoZIzj0EAwQw\n" +
+                "OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" +
+                "VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" +
+                "MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" +
+                "dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwgZswEAYHKoZIzj0C\n" +
+                "AQYFK4EEACMDgYYABAGa2zDLhYQHHCLI3YBqFYJTzrnDIjzwXrxhcRTS8DYkcrjZ\n" +
+                "+Fih1YyNhix0sdjH+3EqElXAHHuVzn3n3hPOtQCWlQCICkErB34S0cvmtRkeW8Fi\n" +
+                "hrR5tvJEzEZjPSgwn81kKyhV2L70je6i7Cw884Va8bODckpgw0vTmbQb7T9dupkv\n" +
+                "1aNCMEAwHQYDVR0OBBYEFHuqeaRJ3Vk08IZsUccw9M7FgYooMB8GA1UdIwQYMBaA\n" +
+                "FEAivFrtaq2pQJ4cW4pEQML3aym9MAoGCCqGSM49BAMEA4GMADCBiAJCAb33KHdY\n" +
+                "WDbusORWoY8Euglpd5zsF15hJsk7wtpD5HST1/NWmdCx405w+TV6a9Gr4VPHeaIQ\n" +
+                "99i/+f237ALL5p6IAkIBbwwFL1vt3c/bx+niyuffQPNjly80rdC9puqAqriSiboS\n" +
+                "efhxjidJ9HLaIRCMEPyd6vAsC8mO8YvL1uCuEQLsiGM=\n" +
+                "-----END CERTIFICATE-----",
+                "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB8C/2OX2Dt9vFszzV\n" +
+                "hcAe0CbkMlvu9uQ/L7Vz88heuIj0rUZIPGshvgIJt1hCMT8HZxYHvDa4lbUvqjFB\n" +
+                "+zafvPWhgYkDgYYABAGa2zDLhYQHHCLI3YBqFYJTzrnDIjzwXrxhcRTS8DYkcrjZ\n" +
+                "+Fih1YyNhix0sdjH+3EqElXAHHuVzn3n3hPOtQCWlQCICkErB34S0cvmtRkeW8Fi\n" +
+                "hrR5tvJEzEZjPSgwn81kKyhV2L70je6i7Cw884Va8bODckpgw0vTmbQb7T9dupkv\n" +
+                "1Q=="),
+
+        EE_RSA_2048(
+                "RSA",
+                // SHA256withRSA, 2048 bits
+                // Validity
+                //     Not Before: May 22 07:18:16 2018 GMT
+                //     Not After : May 17 07:18:16 2038 GMT
+                // Authority Key Identifier:
+                //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+                "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+                "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
+                "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+                "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +
+                "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" +
+                "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" +
+                "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" +
+                "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" +
+                "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" +
+                "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" +
+                "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" +
+                "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" +
+                "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" +
+                "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" +
+                "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" +
+                "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" +
+                "e57NnbT7KM+Grw==\n" +
+                "-----END CERTIFICATE-----",
+                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" +
+                "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" +
+                "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" +
+                "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" +
+                "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" +
+                "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" +
+                "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" +
+                "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" +
+                "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" +
+                "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" +
+                "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" +
+                "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" +
+                "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" +
+                "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" +
+                "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" +
+                "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" +
+                "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" +
+                "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" +
+                "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" +
+                "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" +
+                "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" +
+                "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" +
+                "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" +
+                "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" +
+                "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" +
+                "qAL3go42DYeYhu/WnECMeis="),
+
+        EE_EC_RSA_SECP256R1(
+                "EC",
+                // SHA256withRSA, curve secp256r1
+                // Validity
+                //     Not Before: May 22 07:18:16 2018 GMT
+                //     Not After : May 21 07:18:16 2028 GMT
+                // Authority Key Identifier:
+                //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+                "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+                "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
+                "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+                "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" +
+                "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" +
+                "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" +
+                "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" +
+                "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" +
+                "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" +
+                "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" +
+                "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" +
+                "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" +
+                "-----END CERTIFICATE-----",
+                "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" +
+                "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" +
+                "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT"),
+
+        EE_DSA_2048(
+                "DSA",
+                // SHA256withDSA, 2048 bits
+                // Validity
+                //     Not Before: May 22 07:18:20 2018 GMT
+                //     Not After : May 17 07:18:20 2038 GMT
+                // Authority Key Identifier:
+                //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
+                "-----BEGIN CERTIFICATE-----\n" +
+                "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+                "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+                "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" +
+                "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+                "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" +
+                "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" +
+                "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" +
+                "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" +
+                "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" +
+                "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" +
+                "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" +
+                "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" +
+                "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" +
+                "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" +
+                "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" +
+                "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" +
+                "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" +
+                "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" +
+                "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" +
+                "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" +
+                "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" +
+                "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" +
+                "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" +
+                "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" +
+                "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" +
+                "-----END CERTIFICATE-----",
+                "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" +
+                "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" +
+                "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" +
+                "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" +
+                "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" +
+                "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" +
+                "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" +
+                "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" +
+                "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" +
+                "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" +
+                "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" +
+                "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" +
+                "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw=");
+
+        final String keyAlgo;
+        final String certStr;
+        final String privKeyStr;
+
+        Cert(String keyAlgo, String certStr, String privKeyStr) {
+            this.keyAlgo = keyAlgo;
+            this.certStr = certStr;
+            this.privKeyStr = privKeyStr;
+        }
+    }
 }
--- a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java	Tue Jul 02 12:03:49 2019 -0400
@@ -26,7 +26,7 @@
 
 /**
  * @test
- * @bug 8080462
+ * @bug 8080462 8226651
  * @summary Ensure that PSS key and params check are implemented properly
  *         regardless of call sequence
  * @library /test/lib ..
@@ -57,12 +57,19 @@
         }
         // NOTE: key length >= (digest length + 2) in bytes
         // otherwise, even salt length = 0 would not work
-        runTest(p, 1024, "SHA-384");
-        runTest(p, 1040, "SHA-512");
+        runTest(p, 1024, "SHA-256", "SHA-256");
+        runTest(p, 1024, "SHA-256", "SHA-384");
+        runTest(p, 1024, "SHA-256", "SHA-512");
+        runTest(p, 1024, "SHA-384", "SHA-256");
+        runTest(p, 1024, "SHA-384", "SHA-384");
+        runTest(p, 1024, "SHA-384", "SHA-512");
+        runTest(p, 1040, "SHA-512", "SHA-256");
+        runTest(p, 1040, "SHA-512", "SHA-384");
+        runTest(p, 1040, "SHA-512", "SHA-512");
     }
 
-    private void runTest(Provider p, int keySize, String hashAlg)
-            throws Exception {
+    private void runTest(Provider p, int keySize, String hashAlg,
+            String mgfHashAlg) throws Exception {
         System.out.println("Testing [" + keySize + " " + hashAlg + "]");
 
         // create a key pair with the supplied size
@@ -72,9 +79,9 @@
 
         int bigSaltLen = keySize/8 - 14;
         AlgorithmParameterSpec paramsBad = new PSSParameterSpec(hashAlg,
-            "MGF1", new MGF1ParameterSpec(hashAlg), bigSaltLen, 1);
+            "MGF1", new MGF1ParameterSpec(mgfHashAlg), bigSaltLen, 1);
         AlgorithmParameterSpec paramsGood = new PSSParameterSpec(hashAlg,
-            "MGF1", new MGF1ParameterSpec(hashAlg), 0, 1);
+            "MGF1", new MGF1ParameterSpec(mgfHashAlg), 0, 1);
 
         PrivateKey priv = kp.getPrivate();
         PublicKey pub = kp.getPublic();
--- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java	Tue Jul 02 12:03:49 2019 -0400
@@ -27,7 +27,7 @@
 
 /*
  * @test
- * @bug 8080462
+ * @bug 8080462 8226651
  * @summary testing interoperability of PSS signatures of PKCS11 provider
  *         against SunRsaSign provider
  * @library /test/lib ..
@@ -64,42 +64,31 @@
         KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p);
         kpg.initialize(3072);
         KeyPair kp = kpg.generateKeyPair();
-        boolean status;
-        try {
-            status = runTest(sigSunRsaSign, sigPkcs11, kp);
-            status &= runTest(sigPkcs11, sigSunRsaSign, kp);
-        } catch (Exception e) {
-            System.out.println("Unexpected exception: " + e);
-            e.printStackTrace(System.out);
-            status = false;
-        }
 
-        if (!status) {
-            throw new RuntimeException("One or more test failed");
-        }
+        runTest(sigSunRsaSign, sigPkcs11, kp);
+        runTest(sigPkcs11, sigSunRsaSign, kp);
+
         System.out.println("Test passed");
     }
 
-    static boolean runTest(Signature signer, Signature verifier, KeyPair kp) throws Exception {
+    static void runTest(Signature signer, Signature verifier, KeyPair kp)
+            throws Exception {
         System.out.println("\tSign using " + signer.getProvider().getName());
         System.out.println("\tVerify using " + verifier.getProvider().getName());
 
-        boolean status;
-        for (String digestAlg : DIGESTS) {
-            System.out.println("\tDigest = " + digestAlg);
-            PSSParameterSpec params = new PSSParameterSpec(digestAlg, "MGF1",
-                    new MGF1ParameterSpec(digestAlg), 0, 1);
-            try {
+        for (String hash : DIGESTS) {
+            for (String mgfHash : DIGESTS) {
+                System.out.println("\tDigest = " + hash);
+                System.out.println("\tMGF = MGF1_" + mgfHash);
+
+                PSSParameterSpec params = new PSSParameterSpec(hash, "MGF1",
+                    new MGF1ParameterSpec(mgfHash), 0, 1);
+
                 signer.setParameter(params);
                 signer.initSign(kp.getPrivate());
                 verifier.setParameter(params);
                 verifier.initVerify(kp.getPublic());
-            } catch (Exception e) {
-                System.out.println("\tERROR: unexpected ex during init" + e);
-                status = false;
-                continue;
-            }
-            try {
+
                 signer.update(MSG);
                 byte[] sigBytes = signer.sign();
                 verifier.update(MSG);
@@ -107,15 +96,9 @@
                 if (isValid) {
                     System.out.println("\tPSS Signature verified");
                 } else {
-                    System.out.println("\tERROR verifying PSS Signature");
-                    status = false;
+                    throw new RuntimeException("ERROR verifying PSS Signature");
                 }
-            } catch (Exception e) {
-                System.out.println("\tERROR: unexpected ex" + e);
-                e.printStackTrace();
-                status = false;
             }
         }
-        return true;
     }
 }
--- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java	Tue Jul 02 12:03:49 2019 -0400
@@ -27,7 +27,7 @@
 
 /**
  * @test
- * @bug 8080462
+ * @bug 8080462 8226651
  * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider
  * @library /test/lib ..
  * @modules jdk.crypto.cryptoki
@@ -86,17 +86,19 @@
         test(DIGESTS, kpair.getPrivate(), kpair.getPublic(), data);
     }
 
-    private void test(String[] testAlgs, PrivateKey privKey,
+    private void test(String[] digestAlgs, PrivateKey privKey,
             PublicKey pubKey, byte[] data) throws RuntimeException {
         // For signature algorithm, create and verify a signature
-        for (String testAlg : testAlgs) {
-            try {
-                checkSignature(data, pubKey, privKey, testAlg);
-            } catch (NoSuchAlgorithmException | InvalidKeyException |
-                     SignatureException | NoSuchProviderException ex) {
-                throw new RuntimeException(ex);
-            } catch (InvalidAlgorithmParameterException ex2) {
-                System.out.println("Skip test due to " + ex2);
+        for (String hash : digestAlgs) {
+            for (String mgfHash : digestAlgs) {
+                try {
+                    checkSignature(data, pubKey, privKey, hash, mgfHash);
+                } catch (NoSuchAlgorithmException | InvalidKeyException |
+                         SignatureException | NoSuchProviderException ex) {
+                    throw new RuntimeException(ex);
+                } catch (InvalidAlgorithmParameterException ex2) {
+                    System.out.println("Skip test due to " + ex2);
+                }
             }
         };
     }
@@ -109,13 +111,14 @@
     }
 
     private void checkSignature(byte[] data, PublicKey pub,
-            PrivateKey priv, String mdAlg) throws NoSuchAlgorithmException,
-            InvalidKeyException, SignatureException, NoSuchProviderException,
+            PrivateKey priv, String hash, String mgfHash)
+            throws NoSuchAlgorithmException, InvalidKeyException,
+            SignatureException, NoSuchProviderException,
             InvalidAlgorithmParameterException {
-        System.out.println("Testing against " + mdAlg);
+        System.out.println("Testing against " + hash + " and MGF1_" + mgfHash);
         Signature sig = Signature.getInstance(SIGALG, prov);
         AlgorithmParameterSpec params = new PSSParameterSpec(
-            mdAlg, "MGF1", new MGF1ParameterSpec(mdAlg), 0, 1);
+            hash, "MGF1", new MGF1ParameterSpec(mgfHash), 0, 1);
         sig.setParameter(params);
         sig.initSign(priv);
         for (int i = 0; i < UPDATE_TIMES_HUNDRED; i++) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/ssl/CipherSuite/NamedGroupsWithCipherSuite.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+
+/*
+  * @test
+  * @bug 8224650
+  * @library /javax/net/ssl/templates
+  *          /javax/net/ssl/TLSCommon
+  * @summary Test TLS ciphersuite with each individual supported group
+  * @run main/othervm NamedGroupsWithCipherSuite x25519
+  * @run main/othervm NamedGroupsWithCipherSuite x448
+  * @run main/othervm NamedGroupsWithCipherSuite secp256r1
+  * @run main/othervm NamedGroupsWithCipherSuite secp384r1
+  * @run main/othervm NamedGroupsWithCipherSuite secp521r1
+  * @run main/othervm NamedGroupsWithCipherSuite ffdhe2048
+  * @run main/othervm NamedGroupsWithCipherSuite ffdhe3072
+  * @run main/othervm NamedGroupsWithCipherSuite ffdhe4096
+  * @run main/othervm NamedGroupsWithCipherSuite ffdhe6144
+  * @run main/othervm NamedGroupsWithCipherSuite ffdhe8192
+ */
+public class NamedGroupsWithCipherSuite extends SSLSocketTemplate {
+
+    private static final Protocol[] PROTOCOLS = new Protocol[] {
+            Protocol.TLSV1_3,
+            Protocol.TLSV1_2,
+            Protocol.TLSV1_1,
+            Protocol.TLSV1
+    };
+
+    private static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] {
+            CipherSuite.TLS_AES_128_GCM_SHA256,
+            CipherSuite.TLS_AES_256_GCM_SHA384,
+            CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
+
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+
+            CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+
+            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+            CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    };
+
+    private String protocol;
+    private String cipher;
+
+    private SSLSocketTemplate.Cert[] trustedCerts = TRUSTED_CERTS;
+    private SSLSocketTemplate.Cert[] endEntityCerts = END_ENTITY_CERTS;
+
+    NamedGroupsWithCipherSuite(
+            String protocol,
+            String cipher,
+            String namedGroup) {
+        this.protocol = protocol;
+        this.cipher = cipher;
+
+        if (cipher.startsWith("TLS_ECDHE_ECDSA")) {
+            switch (namedGroup) {
+            case "secp256r1":
+                trustedCerts = new SSLSocketTemplate.Cert[] {
+                        SSLSocketTemplate.Cert.CA_ECDSA_SECP256R1 };
+                endEntityCerts = new SSLSocketTemplate.Cert[] {
+                        SSLSocketTemplate.Cert.EE_ECDSA_SECP256R1 };
+                break;
+            case "secp384r1":
+                trustedCerts = new SSLSocketTemplate.Cert[] {
+                        SSLSocketTemplate.Cert.CA_ECDSA_SECP384R1 };
+                endEntityCerts = new SSLSocketTemplate.Cert[] {
+                        SSLSocketTemplate.Cert.EE_ECDSA_SECP384R1 };
+                break;
+            case "secp521r1":
+                trustedCerts = new SSLSocketTemplate.Cert[] {
+                        SSLSocketTemplate.Cert.CA_ECDSA_SECP521R1 };
+                endEntityCerts = new SSLSocketTemplate.Cert[] {
+                        SSLSocketTemplate.Cert.EE_ECDSA_SECP521R1 };
+            }
+        }
+    }
+
+    protected SSLContext createClientSSLContext() throws Exception {
+        return createSSLContext(trustedCerts, endEntityCerts,
+                getClientContextParameters());
+    }
+
+    protected SSLContext createServerSSLContext() throws Exception {
+        return createSSLContext(trustedCerts, endEntityCerts,
+                getServerContextParameters());
+    }
+
+    // Servers are configured before clients, increment test case after.
+    @Override
+    protected void configureClientSocket(SSLSocket socket) {
+        socket.setEnabledProtocols(new String[] { protocol });
+        socket.setEnabledCipherSuites(new String[] { cipher });
+    }
+
+    @Override
+    protected void configureServerSocket(SSLServerSocket serverSocket) {
+        serverSocket.setEnabledProtocols(new String[] { protocol });
+        serverSocket.setEnabledCipherSuites(new String[] { cipher });
+    }
+
+    public static void main(String[] args) throws Exception {
+        String namedGroup = args[0];
+
+        System.setProperty("jdk.tls.namedGroups", namedGroup);
+        System.out.println("NamedGroup: " + namedGroup);
+
+        for (Protocol protocol : PROTOCOLS) {
+            for (CipherSuite cipherSuite : CIPHER_SUITES) {
+                if (cipherSuite.supportedByProtocol(protocol)
+                        && groupSupportdByCipher(namedGroup, cipherSuite)) {
+                    System.out.printf("Protocol: %s, cipher suite: %s%n",
+                            protocol, cipherSuite);
+
+                    new NamedGroupsWithCipherSuite(protocol.name,
+                            cipherSuite.name(), namedGroup).run();
+                }
+            }
+        }
+    }
+
+    private static boolean groupSupportdByCipher(String group,
+            CipherSuite cipherSuite) {
+        return (group.startsWith("x")
+                        && xdhGroupSupportdByCipher(cipherSuite))
+                || (group.startsWith("secp")
+                        && ecdhGroupSupportdByCipher(cipherSuite))
+                || (group.startsWith("ffdhe")
+                        && ffdhGroupSupportdByCipher(cipherSuite));
+    }
+
+    private static boolean xdhGroupSupportdByCipher(
+            CipherSuite cipherSuite) {
+        return cipherSuite.keyExAlgorithm == null
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA;
+    }
+
+    private static boolean ecdhGroupSupportdByCipher(
+            CipherSuite cipherSuite) {
+        return cipherSuite.keyExAlgorithm == null
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_ECDSA;
+    }
+
+    private static boolean ffdhGroupSupportdByCipher(
+            CipherSuite cipherSuite) {
+        return cipherSuite.keyExAlgorithm == null
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_RSA;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/util/locale/provider/CalendarDataRegression.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8226876
+ * @summary Test CalendarDataUtility class not throwing AssertionError
+ * @run main/othervm -ea -esa -Djava.locale.providers=HOST CalendarDataRegression
+ */
+
+import java.text.DateFormat;
+import java.util.Locale;
+
+public class CalendarDataRegression {
+    public static void main(String[] args) {
+        // Host locale provider on Windows returns 0 for
+        // firstDayOfWeek/minimalDaysInFirstWeek, which should
+        // default to non-zero value. Otherwise AssertionError
+        // will be thrown.
+        DateFormat.getDateInstance(DateFormat.FULL, Locale.US);
+    }
+}
--- a/test/langtools/tools/javac/diags/examples/BreakOutsideSwitchExpression.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/diags/examples/BreakOutsideSwitchExpression.java	Tue Jul 02 12:03:49 2019 -0400
@@ -30,7 +30,8 @@
     int t(int i) {
         OUT: while (true) {
             return switch (i) {
-                default: break OUT;
+                case 0: break OUT;
+                default: yield 0;
             };
         }
         return -1;
--- a/test/langtools/tools/javac/diags/examples/ContinueOutsideSwitchExpression.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/diags/examples/ContinueOutsideSwitchExpression.java	Tue Jul 02 12:03:49 2019 -0400
@@ -30,7 +30,8 @@
     int t(int i) {
         OUT: while (true) {
             return switch (i) {
-                default: continue OUT;
+                case 0: continue OUT;
+                default: yield 0;
             };
         }
     }
--- a/test/langtools/tools/javac/diags/examples/ReturnOutsideSwitchExpression.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/diags/examples/ReturnOutsideSwitchExpression.java	Tue Jul 02 12:03:49 2019 -0400
@@ -29,7 +29,8 @@
 class ReturnOutsideSwitchExpression {
     int t(int i) {
         return switch (i) {
-            default: return -1;
+            case 0: return -1;
+            default: yield 0;
         };
     }
 }
--- a/test/langtools/tools/javac/diags/examples/RuleCompletesNormally.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/diags/examples/RuleCompletesNormally.java	Tue Jul 02 12:03:49 2019 -0400
@@ -29,7 +29,8 @@
 class RuleCompletesNormally {
     public String convert(int i) {
         return switch (i) {
-            default -> {}
+            case 0 -> {}
+            default -> "";
         };
     }
 }
--- a/test/langtools/tools/javac/diags/examples/SwitchExpressionCompletesNormally.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressionCompletesNormally.java	Tue Jul 02 12:03:49 2019 -0400
@@ -29,6 +29,7 @@
 class SwitchExpressionCompletesNormally {
     public String convert(int i) {
         return switch (i) {
+            case 0: yield "";
             default:
         };
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressionNoResultExpressions.java	Tue Jul 02 12:03:49 2019 -0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.switch.expression.no.result.expressions
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class SwitchExpressionCompletesNormally {
+    public String convert(int i) {
+        return switch (i) {
+            default -> throw new AssertionError();
+        };
+    }
+}
--- a/test/langtools/tools/javac/switchexpr/EmptySwitch.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/EmptySwitch.java	Tue Jul 02 12:03:49 2019 -0400
@@ -23,15 +23,29 @@
 
 /*
  * @test
- * @bug 8206986
- * @summary Verify than an empty switch expression is rejected.
- * @compile/fail/ref=EmptySwitch.out --enable-preview -source ${jdk.version} -XDrawDiagnostics EmptySwitch.java
+ * @bug 8206986 8226510
+ * @summary Verify than a switch that does not yield a value is rejected.
+ * @compile/fail/ref=EmptySwitch.out --enable-preview -source ${jdk.version} -XDrawDiagnostics -XDshould-stop.at=FLOW EmptySwitch.java
  */
 
 public class EmptySwitch {
     private void print(EmptySwitchEnum t) {
         (switch (t) {
         }).toString();
+        (switch (t) {
+            default -> throw new IllegalStateException();
+        }).toString();
+        (switch (t) {
+            default: throw new IllegalStateException();
+        }).toString();
+        (switch (0) {
+            case 0: yield "";
+            default:
+        }).toString();
+        (switch (0) {
+            case 0 -> { yield ""; }
+            default -> { }
+        }).toString();
     }
 
     enum EmptySwitchEnum {
--- a/test/langtools/tools/javac/switchexpr/EmptySwitch.out	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/EmptySwitch.out	Tue Jul 02 12:03:49 2019 -0400
@@ -1,4 +1,8 @@
 EmptySwitch.java:33:10: compiler.err.switch.expression.empty
+EmptySwitch.java:35:10: compiler.err.switch.expression.no.result.expressions
+EmptySwitch.java:38:10: compiler.err.switch.expression.no.result.expressions
+EmptySwitch.java:44:9: compiler.err.switch.expression.completes.normally
+EmptySwitch.java:47:26: compiler.err.rule.completes.normally
 - compiler.note.preview.filename: EmptySwitch.java
 - compiler.note.preview.recompile
-1 error
+5 errors
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.java	Tue Jul 02 12:03:49 2019 -0400
@@ -41,9 +41,11 @@
         }
         }
         j: print(switch (i) {
+            case 0: yield 0;
             default: break j;
         }, 0);
         j2: print(switch (i) {
+            case 0: yield 0;
             default: break j2;
         }, 0);
         return null;
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.out	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.out	Tue Jul 02 12:03:49 2019 -0400
@@ -5,8 +5,8 @@
 ExpressionSwitchBreaks2.java:30:29: compiler.err.undef.label: UNKNOWN
 ExpressionSwitchBreaks2.java:40:17: compiler.err.no.switch.expression
 ExpressionSwitchBreaks2.java:40:29: compiler.err.cant.resolve.location: kindname.variable, undef, , , (compiler.misc.location: kindname.class, ExpressionSwitchBreaks2, null)
-ExpressionSwitchBreaks2.java:44:22: compiler.err.break.outside.switch.expression
-ExpressionSwitchBreaks2.java:47:22: compiler.err.break.outside.switch.expression
+ExpressionSwitchBreaks2.java:45:22: compiler.err.break.outside.switch.expression
+ExpressionSwitchBreaks2.java:49:22: compiler.err.break.outside.switch.expression
 - compiler.note.preview.filename: ExpressionSwitchBreaks2.java
 - compiler.note.preview.recompile
-9 errors
+9 errors
\ No newline at end of file
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchFlow.java	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFlow.java	Tue Jul 02 12:03:49 2019 -0400
@@ -22,6 +22,7 @@
     private String test3(int i) {
         return switch (i) {
             case 0 -> {}
+            case 1 -> "";
             default -> throw new IllegalStateException();
         };
     }
@@ -40,17 +41,20 @@
     private String test6(int i) {
         return switch (i) {
             case 0 -> throw new IllegalStateException();
+            case 1 -> "";
             default -> {}
         };
     }
     private String test7(int i) {
         return switch (i) {
             case 0: throw new IllegalStateException();
+            case 1: yield "";
             default:
         };
     }
     private String test8(int i) {
         return switch (i) {
+            case 1: yield "";
             case 0: i++;
             default: {
             }
@@ -58,6 +62,7 @@
     }
     private String test9(int i) {
         return switch (i) {
+            case 1: yield "";
             case 0:
             default:
                 System.err.println();
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchFlow.out	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFlow.out	Tue Jul 02 12:03:49 2019 -0400
@@ -1,12 +1,12 @@
 ExpressionSwitchFlow.java:11:24: compiler.err.rule.completes.normally
 ExpressionSwitchFlow.java:18:13: compiler.err.rule.completes.normally
 ExpressionSwitchFlow.java:24:24: compiler.err.rule.completes.normally
-ExpressionSwitchFlow.java:31:25: compiler.err.rule.completes.normally
-ExpressionSwitchFlow.java:37:25: compiler.err.rule.completes.normally
-ExpressionSwitchFlow.java:43:25: compiler.err.rule.completes.normally
-ExpressionSwitchFlow.java:50:9: compiler.err.switch.expression.completes.normally
-ExpressionSwitchFlow.java:57:9: compiler.err.switch.expression.completes.normally
-ExpressionSwitchFlow.java:64:9: compiler.err.switch.expression.completes.normally
+ExpressionSwitchFlow.java:32:25: compiler.err.rule.completes.normally
+ExpressionSwitchFlow.java:38:25: compiler.err.rule.completes.normally
+ExpressionSwitchFlow.java:45:25: compiler.err.rule.completes.normally
+ExpressionSwitchFlow.java:53:9: compiler.err.switch.expression.completes.normally
+ExpressionSwitchFlow.java:61:9: compiler.err.switch.expression.completes.normally
+ExpressionSwitchFlow.java:69:9: compiler.err.switch.expression.completes.normally
 - compiler.note.preview.filename: ExpressionSwitchFlow.java
 - compiler.note.preview.recompile
 9 errors
--- a/test/langtools/tools/javac/switchexpr/WrongBreakTest.out	Mon Jul 01 18:43:02 2019 -0400
+++ b/test/langtools/tools/javac/switchexpr/WrongBreakTest.out	Tue Jul 02 12:03:49 2019 -0400
@@ -1,8 +1,9 @@
 WrongBreakTest.java:36:41: compiler.err.illegal.start.of.expr
 WrongBreakTest.java:35:39: compiler.err.break.outside.switch.expression
+WrongBreakTest.java:35:17: compiler.err.switch.expression.no.result.expressions
 WrongBreakTest.java:36:9: compiler.err.ref.ambiguous: test, kindname.method, test(int), WrongBreakTest, kindname.method, test(java.lang.Object), WrongBreakTest
 WrongBreakTest.java:38:13: compiler.err.no.switch.expression
 WrongBreakTest.java:41:13: compiler.err.no.switch.expression
 - compiler.note.preview.filename: WrongBreakTest.java
 - compiler.note.preview.recompile
-5 errors
+6 errors