Package: mockselector
MockSelectorDescriptionThis is a collection of Python classes designed to help to test TCP servers
based on selectors. Themockselectorpackage provides everything needed to easily write
unittest TestCases simulating incoming connections and the associated
input dataInstallationFrom PyPIStarting from 0.1.1,mockselectoris available on PyPI. If you just want to
use it in your projects, it is the recommended way:pip install mockselectorOf course, this can be done in a relevant venv if you do not want to have it
in your main installation.Note: thetestfolder is only available in the source distribution.From GithubThis is the recommended way if you want to contribute or simply tweakmockselectorto your own requirements. You can get a local copy by
downloading a zipfile but if you want to make changes, you should
rather clone the repository to have access to allgitgoodies:git clone https://github.com/s-ball/MockSelector.gitYou can then install it in your main Python installation or in a venv with:pip install -e .or on Windows with the launcher:py -m pip install -e .pipshould be used to install it for the first time in order to havesetuptools-scmto generate theversion.pyfile from git metadata.
Once this is done,setup.pycan be used with no special issue.Alternatively you can manually installsetuptools-scm:pip install setuptools-scm
python setup.py installSpecial handling ofversion.py:mockselectorrelies onsetuptools-scmto automatically extract a
version number from git metadata and store it in aversion.pyfile
for later use. The requires the availability of bothgit(which should
not be a problem when the project is downloaded from Github), andsetuptools-scm. If it fails because one is not available or because
git metadata is not there (if you only downloaded a zip archive from
Github), the version is set to 0.0.0For that reason, if you do not use git to download the sources, you
should download a source distribution from PyPI, because the latter
contains a validversion.pypipuses thepyproject.tomlfile with respect to PEP-518 and
PEP-517 to know thatsetuptools-scmis required before the build.Basic useOnce installed, you can easily import it in your tests.from mockselector.selector import MockSocket, ListenSocket, MockSelectorMockSelectoris aselectors.BaseSelectorsubclass. At creation time it
takes an iterable of objects. Those objects can be:asocket.socket(or aMock) that will be returned by aselectcall
along with anEVENT_READeventa pair(socket, event)that will be returned - this allows to passEVENT_WRITEeventsan iterable of above elements. They will be returned in a list by a
singleselectcall assimultaneouseventsMockSocketis a specialization of aMock(socket.socket). Its initializer
takes an iterable of byte strings or functions returning byte strings.
The functions can be used as a run time side effect to set a flag in a
server and allow a clean exit from the main loop.
The byte strings are returned one at a time by therecvmethod. When
the iterable is exhausted,recvreturns an empty byte string (b'')
to mimic a client close or shutdown on the socket.ListenSocketis used to mimic a listening socket. Its initializer takes
an iterable ofsocket.socketobjects (including plainMockorMockSocketobjects) or callables returning an object like that.
The socket objects are returned one at a time by theacceptmethod.Typical useFacing a main server loop close to:...
        s = socket.socket()
        s.bind(('0.0.0.0', self.port))
        s.listen()
        sel = DefaultSelector()
        sel.register(s, EVENT_READ)
        while not self.stop:
            for key, event in sel.select():
                if key.fileobj == s:
                    c, _ = s.accept()
                    sel.register(c, EVENT_READ)
                else:
                    c = key.fileobj
                    data = c.recv(1024)
                    if len(data) == 0:
                        sel.unregister(c)
                        c.close()
                    else:
                        # process received data
                        ...You can do:def test_run_stop(self):
        def do_stop(serv):
            serv.stop = True
            return b''
        serv = ...                  # an instance or the serveur to test
        c1 = MockSocket([...])      # a client with its data
        c2 = MockSocket([..., lambda: do_stop(serv)]) # another client asking for end of server loop
        s = ListenSocket((c1, c2))
        sel = MockSelector([s, c1, s, c2, c2, (c1, c2), c1, c2, c2]) # ordered list of events
        with patch('socket.socket') as socket, \
                patch('miniserv.DefaultSelector') as selector:
            socket.return_value = s
            selector.return_value = sel
            serv.run()You can find a full code example in theminiserv.pyandtest_miniserv.pyfiles in the tests folderAdvanced use and contributionIf you want to tailor the package, it already contains a number of tests.
You can run all of them from the top folder:python setup.py install -e    # edit mode of install to use the local folder
python -m unittest discoverI will be glad to receive issues that would help to improve this project...Disclaimer: beta qualityEven if the package has a nice test coverage (> 95%), it currently only
contains what I need to test another project of mine. It might not meet
your own requirements, or main contain Still Unidentified Bugs...It is still a 0.x version, so the API is not guaranteed to be stable.LicenseThat work is licenced under a MIT Licence. SeeLICENSE.txt