Add API client tests.

This commit is contained in:
Jon Chambers 2020-12-05 12:54:04 -05:00 committed by Jon Chambers
parent a9f0812fde
commit ebb2e05cda
3 changed files with 177 additions and 0 deletions

113
service/test/api_client_test.py Executable file
View 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)

View File

@ -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) ]

View 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))