Rework `Server` unit tests to use stubbing and a spy

This reworks the `Server` unit tests to not actually build
sockets. This is a lot of overhead for a test suite and causes
hard to debug errors when things fail (can't bind to address,
etc...). This switches to using a server spy and fake sockets for
testing the behavior of the `Server`. This results in faster and
more robust tests with simpler setup. This also avoids all the
management of ensuring the `TCPServer` has been shutdown.

A full test using an actual `TCPServer` and sockets is still done
in the system tests to ensure the spy is not hiding issues.