From 7568e0d5d30ff21cf0b4a25311fb940f03ef9974 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sat, 19 Dec 2015 01:11:57 +0100 Subject: [PATCH] Basic architecture. --- .gitignore | 4 ++ irctest/__init__.py | 0 irctest/__main__.py | 38 ++++++++++++++++ irctest/basecontrollers.py | 9 ++++ irctest/cases.py | 28 ++++++++++++ irctest/clienttests/__init__.py | 8 ++++ irctest/clienttests/test_cap.py | 12 +++++ irctest/controllers/__init__.py | 0 irctest/controllers/limnoria.py | 43 ++++++++++++++++++ setup.py | 80 +++++++++++++++++++++++++++++++++ 10 files changed, 222 insertions(+) create mode 100644 irctest/__init__.py create mode 100644 irctest/__main__.py create mode 100644 irctest/basecontrollers.py create mode 100644 irctest/cases.py create mode 100644 irctest/clienttests/__init__.py create mode 100644 irctest/clienttests/test_cap.py create mode 100644 irctest/controllers/__init__.py create mode 100644 irctest/controllers/limnoria.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index ba74660..011fbf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Text editors +*~ +*.swp + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/irctest/__init__.py b/irctest/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/irctest/__main__.py b/irctest/__main__.py new file mode 100644 index 0000000..c53feef --- /dev/null +++ b/irctest/__main__.py @@ -0,0 +1,38 @@ +import sys +import unittest +import argparse +import unittest +import functools +import importlib +from .cases import _IrcTestCase +from .basecontrollers import BaseClientController, BaseServerController + +def main(args): + try: + module = importlib.import_module(args.module) + except ImportError: + print('Cannot import module {}'.format(args.module), file=sys.stderr) + exit(1) + + controller_class = module.get_irctest_controller_class() + if issubclass(controller_class, BaseClientController): + module = 'irctest.clienttests' + elif issubclass(controller_class, BaseClientController): + module = 'irctest.servertests' + else: + print('{}.Controller should be a subclass of ' + 'irctest.basecontroller.Base{Client,Server}Controller' + .format(args.module), + file=sys.stderr) + exit(1) + _IrcTestCase.controllerClass = controller_class + unittest.main(module=module, argv=[sys.argv[0], 'discover']) + + +parser = argparse.ArgumentParser( + description='A script to test interoperability of IRC software.') +parser.add_argument('module', type=str, + help='The module used to run the tested program.') + +args = parser.parse_args() +main(args) diff --git a/irctest/basecontrollers.py b/irctest/basecontrollers.py new file mode 100644 index 0000000..9d7c6fa --- /dev/null +++ b/irctest/basecontrollers.py @@ -0,0 +1,9 @@ +class _BaseController: + pass + +class BaseClientController(_BaseController): + def run(self, hostname, port, authentication): + raise NotImplementedError() + +class BaseServerController(_BaseController): + pass diff --git a/irctest/cases.py b/irctest/cases.py new file mode 100644 index 0000000..95df7ef --- /dev/null +++ b/irctest/cases.py @@ -0,0 +1,28 @@ +import socket +import unittest + +class _IrcTestCase(unittest.TestCase): + controllerClass = None # Will be set by __main__.py + +class ClientTestCase(_IrcTestCase): + def setUp(self): + self.controller = self.controllerClass() + self._setUpServer() + def tearDown(self): + del self.controller + self.conn_file.close() + self.conn.close() + self.server.close() + + def _setUpServer(self): + """Creates the server and make it listen.""" + self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server.bind(('', 0)) # Bind any free port + self.server.listen(1) + def acceptClient(self): + """Make the server accept a client connection. Blocking.""" + (self.conn, addr) = self.server.accept() + self.conn_file = self.conn.makefile() + + def getLine(self): + return self.conn_file.readline().strip() diff --git a/irctest/clienttests/__init__.py b/irctest/clienttests/__init__.py new file mode 100644 index 0000000..ba11145 --- /dev/null +++ b/irctest/clienttests/__init__.py @@ -0,0 +1,8 @@ +import os +import unittest + + +def discover(): + ts = unittest.TestSuite() + ts.addTests(unittest.defaultTestLoader.discover(os.path.dirname(__file__))) + return ts diff --git a/irctest/clienttests/test_cap.py b/irctest/clienttests/test_cap.py new file mode 100644 index 0000000..6d009da --- /dev/null +++ b/irctest/clienttests/test_cap.py @@ -0,0 +1,12 @@ +from irctest.cases import ClientTestCase + +class CapTestCase(ClientTestCase): + def testSendCap(self): + (hostname, port) = self.server.getsockname() + self.controller.run( + hostname=hostname, + port=port, + authentication=None, + ) + self.acceptClient() + print(self.getLine()) diff --git a/irctest/controllers/__init__.py b/irctest/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/irctest/controllers/limnoria.py b/irctest/controllers/limnoria.py new file mode 100644 index 0000000..f3b66b8 --- /dev/null +++ b/irctest/controllers/limnoria.py @@ -0,0 +1,43 @@ +import os +import tempfile +import subprocess + +from irctest.basecontrollers import BaseClientController + +TEMPLATE_CONFIG = """ +supybot.networks: testnet +supybot.networks.testnet.servers: {hostname}:{port} +""" + +class LimnoriaController(BaseClientController): + def __init__(self): + super().__init__() + self.directory = None + self.proc = None + def __del__(self): + if self.proc: + self.proc.kill() + if self.directory: + self.directory.cleanup() + def open_file(self, name): + assert self.directory + return open(os.path.join(self.directory.name, name), 'a') + + def create_config(self): + self.directory = tempfile.TemporaryDirectory() + with self.open_file('bot.conf'): + pass + + def run(self, hostname, port, authentication): + # Runs a client with the config given as arguments + self.create_config() + with self.open_file('bot.conf') as fd: + fd.write(TEMPLATE_CONFIG.format( + hostname=hostname, + port=port, + )) + self.proc = subprocess.Popen(['supybot', + os.path.join(self.directory.name, 'bot.conf')]) + +def get_irctest_controller_class(): + return LimnoriaController diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b18e4f0 --- /dev/null +++ b/setup.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002-2005, Jeremiah Fincher +# Copyright (c) 2009, James McCoy +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +import os +import sys +from distutils.core import setup + +if sys.version_info < (3, 2, 0): + sys.stderr.write("This script requires Python 3.2 or newer.") + sys.stderr.write(os.linesep) + sys.exit(-1) + + +setup( + name='irctest', + version='0.1', + author='Valentin Lorentz', + url='https://github.com/ProgVal/irctest/', + author_email='progval+irctest@progval.net', + description='A script to test interoperability of IRC software.', + platforms=['linux', 'linux2'], + long_description="""This script aims at testing interoperability of + software using the IRC protocol, by running them against test suites + and making different software communicate with each other..""", + classifiers = [ + 'Development Status :: 2 - Pre-Alpha', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: POSIX', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3 :: Only' + 'Topic :: Communications :: Chat :: Internet Relay Chat', + 'Topic :: Software Development :: Testing', + ], + + # Installation data + packages=[ + 'irctest', + ], + + package_dir={ + 'irctest': 'irctest', + }, + ) + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: