Skip to content

Commit

Permalink
Add basic python integration test (#130)
Browse files Browse the repository at this point in the history
* Add basic python integration test

* Extract pelikan server python handler

* Extract pelikan python client
  • Loading branch information
seppo0010 authored and Yao Yue committed Feb 22, 2017
1 parent 399364b commit 04cca24
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ cscope.out
# CLion
/.idea
lcov

# python compiled files
*.pyc
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,4 @@ script:
- cmake ..
- make -j
- make check
- cd ../test && python -m unittest discover
Empty file added test/integration/__init__.py
Empty file.
50 changes: 50 additions & 0 deletions test/integration/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import unittest

from .pelikan_client import PelikanClient
from .pelikan_server import PelikanServer

SERVER_PORT = 12345
ADMIN_PORT = 12346


class PelikanTest(unittest.TestCase):
reserved_ports = set()

def setUp(self):
self.server = self.getServer(
server_port=SERVER_PORT,
admin_port=ADMIN_PORT
)
self.client = PelikanClient(
server_port=SERVER_PORT,
admin_port=ADMIN_PORT
)

def tearDown(self):
self.server.stop()

def assertRead(self, expected):
read = self.client.read(len(expected))
self.assertEqual(expected, read)


def assertMetrics(self, *args):
stats = self.client.getStats()
for (k, v) in args:
self.assertEqual(
stats.get(k, None),
str(v),
'Expected {} to be {}, got {} instead'.format(
k,
v,
stats.get(k, None),
)
)


class TwemcacheTest(PelikanTest):
def getServer(self, **kwargs):
server = PelikanServer('pelikan_twemcache')
server.start(**kwargs)
server.wait_ready()
return server
38 changes: 38 additions & 0 deletions test/integration/pelikan_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import errno
import socket


class PelikanClient(object):
def __init__(self, server_port, admin_port):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.connect(('localhost', server_port))
self.admin = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.admin.connect(('localhost', admin_port))

def getStats(self):
self.admin.sendall('stats\r\n')
data = ''
self.admin.setblocking(False)
while True:
try:
data += self.admin.recv(1024)
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
if len(data) == 0:
continue
else:
break
else:
raise
self.admin.setblocking(True)
# this NULL is kinda unexpected for me
if data[-6:] != 'END\r\n\0':
raise Exception('Invalid data while fetching stats: {}'.format(data))
return dict(line.split(' ')[1:] for line in data[:-6].strip().split('\r\n'))

def read(self, length):
return self.client.recv(length)

def write(self, data):
self.client.sendall(data)
39 changes: 39 additions & 0 deletions test/integration/pelikan_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os
import subprocess
import tempfile


class PelikanServer(object):
@staticmethod
def default_path():
return os.path.realpath(os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'../../_build/_bin'
))

def __init__(self, executable):
self.executable = executable

def start(self, **kwargs):
self.config_file = tempfile.NamedTemporaryFile()
self.config_file.write('\n'.join(('{}: {}'.format(k, v) for (k, v) in kwargs.items())))
self.config_file.flush()

executable = os.path.join(
os.getenv('PELIKAN_BIN_PATH', PelikanServer.default_path()),
self.executable
)
self.server = subprocess.Popen((executable, self.config_file.name),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

def wait_ready(self):
# wait for the port to be listening; no great "ready" output present
# but it lists all configs, so this must exist
while 'name: server_port' not in self.server.stdout.readline():
pass

def stop(self):
self.server.kill()
7 changes: 7 additions & 0 deletions test/integration/test_twemcache_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .base import TwemcacheTest

class TwemcacheBasicTest(TwemcacheTest):
def test_miss(self):
self.client.write('get foo\r\n')
self.assertRead('END')
self.assertMetrics(('request_parse', 1), ('get', 1), ('get_key_miss', 1))

0 comments on commit 04cca24

Please sign in to comment.