-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic python integration test (#130)
* Add basic python integration test * Extract pelikan server python handler * Extract pelikan python client
- Loading branch information
Showing
7 changed files
with
138 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,3 +37,6 @@ cscope.out | |
# CLion | ||
/.idea | ||
lcov | ||
|
||
# python compiled files | ||
*.pyc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,3 +93,4 @@ script: | |
- cmake .. | ||
- make -j | ||
- make check | ||
- cd ../test && python -m unittest discover |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |