Commit 9861e812 authored by zhifan huang's avatar zhifan huang Committed by Xiaowu Zhang

test: add a test with a client and server

This test create a real client and server, use client to call rpc.
Because not include re6stnet, babel_dump related functions aren't tested

see nexedi/re6stnet!38 (comment 161622)
for detail.
parent 81bc1f09
import os
import unittest
import time
import sqlite3
from pathlib2 import Path
import subprocess
import tempfile
import json
import zlib
from re6st import registry, x509
from re6st.tests.test_network import re6st_wrap
from re6st.tests import tools
DEMO_PATH = Path(__file__).parent.parent.parent.parent / "demo"
DH_FILE = DEMO_PATH / "dh2048.pem"
class dummyNode():
"""fake node to reuse Re6stRegistry
error: node.Popen has destory method which not in subprocess.Popen
"""
def __init__(self):
self.ip = "localhost"
self.Popen = subprocess.Popen
self.pid = os.getpid()
class TestRegistryClentInteract(unittest.TestCase):
@classmethod
def setUpClass(cls):
re6st_wrap.initial()
# if running in net ns, set lo up
subprocess.Popen(["ip", "link", "set", "lo", "up"], stderr=subprocess.PIPE)
def setUp(self):
self.port = 18080
self.url = "http://localhost:{}/".format(self.port)
# not inportant, used in network_config check
self.max_clients = 10
def tearDown(self):
self.server.proc.terminate()
def test_1_main(self):
""" a client interact a server, no re6stnet node test basic function"""
try:
self.server = re6st_wrap.Re6stRegistry(dummyNode(), "2001:db8:42::",
self.max_clients, port=self.port,
recreate=True)
except:
self.skipTest("start registry failed")
client = registry.RegistryClient(self.url)
email = "m1@miku.com"
# simulate the process in conf
# request a token
client.requestToken(email)
# read token from db
db = sqlite3.connect(str(self.server.db), isolation_level=None)
count = 0
token = None
while not token:
time.sleep(.1)
token = db.execute("SELECT token FROM token WHERE email=?",
(email,)).fetchone()
count += 1
if count > 100:
raise Exception("Request token failed, no token in database")
# token: tuple[unicode,]
token = str(token[0])
self.assertEqual(client.isToken(token), "1")
# request ca
ca = client.getCa()
# request a cert and get cn
key, csr = tools.generate_csr()
cert = client.requestCertificate(token, csr)
self.assertEqual(client.isToken(token), '', "token should be deleted")
# creat x509.cert object
def write_to_temp(text):
"""text: bytes"""
fp = tempfile.NamedTemporaryFile()
fp.write(text)
# when reopen a fp, python seems reuse the fd, so seek is needed
fp.seek(0)
return fp
fps = [write_to_temp(text) for text in [ca, key, cert]]
ca, key, cert = fps
client.cert = x509.Cert(ca.name, key.name, cert.name)
ca.close()
cert.close()
# cert.decrpty use key file, close after entire test
self.addCleanup(key.close)
# verfiy cn and prefix
prefix = client.cert.prefix
cn = client.getNodePrefix(email)
self.assertEqual(tools.prefix2cn(prefix), cn)
# simulate the process in cache
# just prove works
net_config = client.getNetworkConfig(prefix)
net_config = json.loads(zlib.decompress(net_config))
self.assertEqual(net_config[u'max_clients'], self.max_clients)
# no re6stnet, empty result
bootpeer = client.getBootstrapPeer(prefix)
self.assertEqual(bootpeer, "")
# server should not die
self.assertIsNone(self.server.proc.poll())
#TODO with a registry and some node, test babel_dump related function
if __name__ == "__main__":
unittest.main()
\ No newline at end of file
......@@ -27,12 +27,9 @@ RE6ST_CONF = "re6st-conf"
RE6ST_CONF = "python -m re6st.cli.conf"
def initial():
"""create the workplace and dh file"""
"""create the workplace"""
if not WORK_DIR.exists():
WORK_DIR.mkdir()
if not DH_FILE.exists():
logging.info("create dh file")
call(['openssl', 'dhparam', '-out', str(DH_FILE), '2048'], stderr=PIPE)
def ip_to_serial(ip6):
"""convert ipv6 address to serial"""
......@@ -45,12 +42,13 @@ class Re6stRegistry(object):
"""class run a re6st-registry service on a namespace"""
registry_seq = 0
def __init__(self, node, ip6, client_number, recreate=False):
def __init__(self, node, ip6, client_number, port=80, recreate=False):
self.node = node
# TODO need set once
self.ip = node.ip
self.ip6 = ip6
self.client_number = client_number
self.port = port
self.name = self.generate_name()
self.path = WORK_DIR / self.name
......@@ -72,25 +70,20 @@ class Re6stRegistry(object):
text = f.read()
self.ident = hash(text)
# clear log file
if self.log.exists():
self.log.unlink()
self.clean()
self.run()
# wait the servcice started
p = self.node.Popen(['python', '-c', """if 1:
import socket, time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
s.connect(('localhost', 80))
s.connect(('localhost', {}))
break
except socket.error:
time.sleep(.1)
"""])
""".format(self.port)])
now = time.time()
while time.time() - now < 10:
......@@ -98,8 +91,8 @@ class Re6stRegistry(object):
break
time.sleep(0.1)
else:
p.destroy()
logging.error("registry failed to start, %s", self.name)
p.destroy()
raise Exception("registry failed to start")
logging.info("re6st service started")
......@@ -121,7 +114,7 @@ class Re6stRegistry(object):
cmd =['--ca', self.ca_crt, '--key', self.ca_key, '--dh', DH_FILE,
'--ipv4', '10.42.0.0/16', '8', '--logfile', self.log, '--db', self.db,
'--run', self.run_path, '--hello', '4', '--mailhost', 's', '-v4',
'--client-count', (self.client_number+1)//2]
'--client-count', (self.client_number+1)//2, '--port', self.port]
#convert PosixPath to str, can be remove in python3
cmd = map(str, cmd)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment