@org.junit.Test
	public void testBlocking() throws com.grey.base.GreyException, java.io.IOException
	{
		FileOps.deleteDirectory(rootdir);
		final com.grey.naf.BufferSpec bufspec = new com.grey.naf.BufferSpec(0, 10);
		final String rdwrdata = "This goes into an xmtpool buffer";  //deliberately larger than IOExecWriter's buffer-size
		final String rdonlydata = "This is a read-only buffer";  //deliberately larger than IOExecWriter's buffer-size
		final String initialchar = "z";
		final java.nio.ByteBuffer rdonlybuf = com.grey.base.utils.NIOBuffers.encode(rdonlydata, null, false).asReadOnlyBuffer();

		com.grey.naf.DispatcherDef def = new com.grey.naf.DispatcherDef();
		def.hasNafman = false;
		def.surviveHandlers = false;
		Dispatcher dsptch = Dispatcher.create(def, null, com.grey.logging.Factory.getLogger("no-such-logger"));
		java.nio.channels.Pipe pipe = java.nio.channels.Pipe.open();
		java.nio.channels.Pipe.SourceChannel rep = pipe.source();
		java.nio.channels.Pipe.SinkChannel wep = pipe.sink();
		rep.configureBlocking(false);
		CMW cm = new CMW(dsptch, wep, bufspec);
		org.junit.Assert.assertTrue(cm.isConnected());

		// write to the pipe till it blocks
		org.junit.Assert.assertFalse(cm.chanwriter.isBlocked());
		int pipesize = 0;
		while (cm.write(initialchar)) pipesize++;
		org.junit.Assert.assertTrue(cm.chanwriter.isBlocked());
		String expectdata = initialchar;
		// pipe has now blocked, so do some more sends
		for (int loop = 0; loop != 3; loop++) {
			cm.chanwriter.transmit(rdonlybuf);
			org.junit.Assert.assertTrue(cm.chanwriter.isBlocked());
			expectdata += rdonlydata;
		}
		com.grey.base.utils.ByteChars bc = new com.grey.base.utils.ByteChars(rdwrdata);
		for (int loop = 0; loop != 10; loop++) {
			boolean done = cm.write(bc);
			org.junit.Assert.assertFalse(done);
			org.junit.Assert.assertTrue(cm.chanwriter.isBlocked());
			expectdata += rdwrdata;
		}
		//need to do this send to test main enqueue() loop
		java.nio.ByteBuffer niobuf = com.grey.base.utils.NIOBuffers.encode(rdwrdata, null, false);
		boolean done = cm.write(niobuf);
		org.junit.Assert.assertFalse(done);
		org.junit.Assert.assertTrue(cm.chanwriter.isBlocked());
		expectdata += rdwrdata;
		int xmitcnt = pipesize + expectdata.length();

		// Read the first pipe-load of data.
		// Even though we allocate a big enough rcvbuf, we're not guaranteed to read it all in one go.
		java.nio.ByteBuffer rcvbuf = com.grey.base.utils.NIOBuffers.create(xmitcnt+10, false); //a few bytes to spare
		int rcvcnt = 0;
		while (rcvcnt < pipesize) {
			int nbytes = rep.read(rcvbuf);
			rcvcnt += nbytes;
			org.junit.Assert.assertTrue("Last read="+nbytes, rcvcnt <= pipesize);
			for (int idx = 0; idx != nbytes; idx++) {
				org.junit.Assert.assertEquals(initialchar.charAt(0), rcvbuf.get(idx));
			}
		}
		//there will be no more data to read till Dispatcher triggers the Writer
		int nbytes = rep.read(rcvbuf);
		org.junit.Assert.assertEquals(0, nbytes);
		org.junit.Assert.assertTrue(cm.chanwriter.isBlocked());
		done = cm.disconnect(); //should be delayed by linger
		org.junit.Assert.assertFalse(done);

		// start the Dispatcher and wait for writer to drain its backlog
		dsptch.start();
		bc = new com.grey.base.utils.ByteChars();
		int rdbytes = 0;
		rcvbuf.clear();
		while ((nbytes = rep.read(rcvbuf)) != -1) {
			if (nbytes == 0) continue;
			for (int idx = 0; idx != nbytes; idx++) {
				bc.append(rcvbuf.get(idx));
			}
			rcvbuf.clear();
			rdbytes += nbytes;
		}
		org.junit.Assert.assertEquals(xmitcnt - pipesize, rdbytes);
		org.junit.Assert.assertTrue(StringOps.sameSeq(expectdata, bc));

		dsptch.stop();
		dsptch.waitStopped();
		synchronized (cm) {
			org.junit.Assert.assertTrue(cm.completed);
		}
		rep.close();
		org.junit.Assert.assertFalse(cm.isConnected());
		org.junit.Assert.assertFalse(dsptch.isRunning());
		org.junit.Assert.assertEquals(bufspec.xmtpool.size(), bufspec.xmtpool.population());
	}