Add API client tests.
This commit is contained in:
parent
a9f0812fde
commit
ebb2e05cda
113
service/test/api_client_test.py
Executable file
113
service/test/api_client_test.py
Executable file
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, signal, atexit, random, unittest
|
||||
|
||||
from util import eprint, gprint, backup_id_to_str, random_id
|
||||
from kbupd import Kbupd
|
||||
from partition import Partition
|
||||
from peer_ca import PeerCa
|
||||
from kbupdapiclient import KbupdApiClient
|
||||
from netem import start_playback
|
||||
|
||||
BACKUP_DATA_LENGTH = 48
|
||||
|
||||
class NetemTestCase(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.ca = PeerCa()
|
||||
|
||||
scripts = os.environ.get('SCRIPT', '').split(',')
|
||||
cls.scripts = scripts if scripts != [''] else []
|
||||
if len(cls.scripts) > 0:
|
||||
cls.netem_threads = start_playback(*cls.scripts)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
if hasattr(cls, 'netem_threads'):
|
||||
for thread in cls.netem_threads:
|
||||
thread.exit.set()
|
||||
thread.join()
|
||||
cls.netem_threads = None
|
||||
|
||||
super().tearDownClass()
|
||||
|
||||
class KbupdTestCase(NetemTestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.partitions = []
|
||||
cls.enclave_name = "test"
|
||||
|
||||
partition = Partition(cls.ca)
|
||||
cls.partitions.append(partition)
|
||||
gprint("Started service %s" % partition.service_id)
|
||||
gprint("Started partition %s" % partition.get_spec())
|
||||
gprint()
|
||||
|
||||
partition = partition.split_partition()
|
||||
partition.start_partition()
|
||||
cls.partitions.append(partition)
|
||||
gprint("Started service %s" % partition.service_id)
|
||||
gprint("Started 2nd partition %s" % partition.get_spec())
|
||||
gprint()
|
||||
cls.partitions[0].wait_partition_started_source()
|
||||
cls.partitions[0].resume_partition()
|
||||
cls.partitions[0].pause_partition()
|
||||
cls.partitions[0].resume_partition()
|
||||
cls.partitions[0].wait_partition_source()
|
||||
partition.wait_partition_destination()
|
||||
partition.finish_partition()
|
||||
cls.partitions[0].finish_partition()
|
||||
|
||||
cls.frontend = Kbupd(1337, "frontend", cls.ca,
|
||||
"--enclave-name", cls.enclave_name,
|
||||
"--max-backup-data-length", str(BACKUP_DATA_LENGTH),
|
||||
"--partitions", ';'.join([ p.get_spec() for p in cls.partitions ]))
|
||||
gprint("Started frontend %s" % cls.frontend.node_id)
|
||||
gprint()
|
||||
|
||||
cls.backup_data = random_id(BACKUP_DATA_LENGTH)
|
||||
cls.backup_pin = random_id(32)
|
||||
|
||||
cls.client = KbupdApiClient(cls.frontend, cls.enclave_name, cls.partitions[0].service_id, "test_%030x" % random.randrange(16**32))
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
for p in cls.partitions:
|
||||
p.kill()
|
||||
cls.frontend.kill()
|
||||
|
||||
super().tearDownClass()
|
||||
|
||||
def test_00_valid_requests(self):
|
||||
client = self.client
|
||||
|
||||
# Verify we're starting without stale data
|
||||
print(client.request(r"status=Missing", "restore", pin = self.backup_pin, valid_from = 0))
|
||||
|
||||
client.request(r"status=Ok", "backup", pin = self.backup_pin, valid_from = 0)
|
||||
client.request(r"status=Ok", "restore", pin = self.backup_pin, valid_from = 0)
|
||||
client.request(None, "delete")
|
||||
client.request(r"status=Missing", "restore", pin = self.backup_pin, valid_from = 0)
|
||||
|
||||
client.request(r"status=Ok", "backup", pin = self.backup_pin, valid_from = 0)
|
||||
client.request(r"status=Ok", "restore", pin = self.backup_pin, valid_from = 0)
|
||||
client.request(None, "delete_all")
|
||||
client.request(r"status=Missing", "restore", pin = self.backup_pin, valid_from = 0)
|
||||
|
||||
def kill_all(*args):
|
||||
Kbupd.kill_all()
|
||||
raise(Exception("SIGTERM"))
|
||||
|
||||
def cleanup():
|
||||
if len(Kbupd.processes) > 0:
|
||||
Kbupd.kill_all()
|
||||
|
||||
if __name__ == "__main__":
|
||||
signal.signal(signal.SIGTERM, kill_all)
|
||||
atexit.register(cleanup)
|
||||
unittest.installHandler()
|
||||
unittest.main(failfast=True)
|
||||
@ -12,6 +12,7 @@ class Kbupd():
|
||||
if os.path.isfile(os.path.join(bd, "kbupd")):
|
||||
self.kbupd_bin = os.path.join(bd, "kbupd")
|
||||
self.kbupctl_bin = os.path.join(bd, "kbupctl")
|
||||
self.kbupd_api_client_bin = os.path.join(bd, "kbupd_api_client")
|
||||
self.kbuptlsd_bin = os.path.join(bd, "kbuptlsd")
|
||||
break
|
||||
for bd in (os.getenv("CONFIG_DIR"), ".", "config"):
|
||||
@ -186,6 +187,12 @@ class Kbupd():
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL, close_fds=True)
|
||||
|
||||
def kbupd_api_client(self, *args):
|
||||
return subprocess.run([self.kbupd_api_client_bin,
|
||||
"--connect", "http://127.0.0.1:%s" % self.api_port, *args],
|
||||
stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, close_fds=True)
|
||||
|
||||
def grep_log(self, regex):
|
||||
with open(self.log_file, 'r') as logfd:
|
||||
return [ line[:-1] for line in logfd if re.search(regex, line) ]
|
||||
|
||||
57
service/test/kbupdapiclient.py
Normal file
57
service/test/kbupdapiclient.py
Normal file
@ -0,0 +1,57 @@
|
||||
import atexit, re, time
|
||||
from datetime import datetime
|
||||
|
||||
from util import eprint
|
||||
|
||||
def timestamp():
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
|
||||
|
||||
class KbupdApiClient():
|
||||
log = None
|
||||
|
||||
def __init__(self, frontend, enclave_name, service_id,
|
||||
username, shared_auth_secret = "0000000000000000000000000000000000000000000000000000000000000000"):
|
||||
self.frontend = frontend
|
||||
self.enclave_name = enclave_name
|
||||
self.service_id = service_id
|
||||
self.username = username
|
||||
self.shared_auth_secret = shared_auth_secret
|
||||
|
||||
if not self.log:
|
||||
KbupdApiClient.log = open("api_client_test.log", 'w')
|
||||
atexit.register(KbupdApiClient.log.close)
|
||||
|
||||
def request(self, regex, subcommand, pin = None, service_id = None, valid_from = None):
|
||||
if subcommand in ("backup", "restore", "delete"):
|
||||
if service_id is None:
|
||||
service_id = self.service_id
|
||||
|
||||
cmd = ["--username", self.username, "--token-secret", self.shared_auth_secret, subcommand]
|
||||
|
||||
if subcommand != "delete_all":
|
||||
cmd.extend(["--enclave-name", self.enclave_name])
|
||||
|
||||
if pin is not None:
|
||||
cmd.extend(["--backup-pin", str(pin)])
|
||||
if service_id is not None:
|
||||
cmd.extend(["--service-id", str(service_id)])
|
||||
if valid_from is not None:
|
||||
cmd.extend(["--valid-from", str(valid_from)])
|
||||
|
||||
self.log.write(timestamp() + " CMD: " + ' '.join(cmd) + '\n')
|
||||
|
||||
kbupd_api_client = self.frontend.kbupd_api_client(*cmd)
|
||||
output = kbupd_api_client.stdout.decode()
|
||||
stderr = kbupd_api_client.stderr.decode()
|
||||
|
||||
self.log.write(timestamp() + " COMPLETED\n")
|
||||
self.log.write(stderr)
|
||||
self.log.flush()
|
||||
|
||||
if regex is not None and re.search(regex, output) == None and re.search(regex, stderr) == None:
|
||||
eprint()
|
||||
eprint("TEST '%s' FAILED, expecting %s, got:" % (" ".join(cmd), regex))
|
||||
eprint(output)
|
||||
raise Exception("Test failed")
|
||||
|
||||
return dict(re.findall(r'(\S+)=(\S*)', output))
|
||||
Loading…
Reference in New Issue
Block a user