This looks good. I think we can put a bit more effort to make this mimic a real behavior.
I think the important part is that we need to fail all pending request and callback correctly (SendThread.cleanup()). Additionally, the client should see the state transition in order disconnected -> session expire. So user can write unit test based on what ZooKeeeper client guarantee.
Here are my suggestions
1. We can add injectConnectionLoss() method. Essentially, we need SendThread to call cleanup() and queue Disconnected event into the queue. We might be able to do this by causing SendThread to exit
2. In injectSessionExpire() method. I think the current approach is good, but we should wait until SendThread exit before queuing SessionExpire event. So it is like invoking injectConnectionLoss() if it isn't already in disconnected state.
3. Unit test should make sure that ZooKeeperTestable behave as expected regarding state transition and pending operations/callbacks.